首页 > 解决方案 > 混合同步/异步日志记录 log4j 不起作用

问题描述

我正在尝试分析和实现混合同步和异步日志记录。我正在使用 Spring Boot 应用程序和 Disruptor API。我的 log4j 配置:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug">
<Appenders>
    <Console name="Console-Appender" target="SYSTEM_OUT">
        <PatternLayout>
            <pattern>
                [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
            </pattern>>
        </PatternLayout>
    </Console>        
</Appenders>
<Loggers>
    <AsyncLogger name="com.example.logging" level="debug">
        <AppenderRef ref="Console-Appender"/>
    </AsyncLogger>
    <Root level="info">
        <AppenderRef ref="Console-Appender"/>            
    </Root>
</Loggers>

演示类 1:

package com.example.logging;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

@SpringBootApplication
public class DemoApplication2 {

static Logger logger = LogManager.getLogger(DemoApplication2.class);

public static void main(String[] args) {
    SpringApplication.run(DemoApplication2.class, args);        
    long startTime = System.currentTimeMillis();
    
    for(int i = 0; i < 2000; i++) { 
        logger.debug("Async : " + i);   
    }
                            
    System.out.println("time taken:: " + (System.currentTimeMillis() - startTime));     
 }

}

使用上面的代码,我期望“System.out”应该在所有“调试”语句的日志记录之前打印,因为我正在为“调试”级别使用异步日志记录。因此,首先会记录少量调试器日志(例如,少量 100 或 150 个),然后应打印 SOP,然后应记录剩余的调试器日志。但是,当我运行我的应用程序时,所有调试器语句首先记录,然后 SOP 打印,这不是预期的结果。此外,如果我在“asynclogger”(<AsyncLogger name="com.example.logging" level="debug" additivity="false">)中使用 additivity="false",那么我可以看到我预期的上述结果。现在我有第二个演示课:

package com.example.logging;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

@SpringBootApplication
public class DemoApplication3 {

static Logger logger = LogManager.getLogger(DemoApplication3.class);

public static void main(String[] args) {
    SpringApplication.run(DemoApplication3.class, args);        
    long startTime = System.currentTimeMillis();                    
    
    for(int i = 0; i < 2000; i++) {
        logger.info("Sync : " + i);
    }
    
    System.out.println("time taken:: " + (System.currentTimeMillis() - startTime));     
 }

}

现在有了上面的课程,我期待所有的同步记录首先和 SOP 应该在所有信息日志之后打印。但是如果将“additivity="false" 添加到我的配置中,那么所有日志都是异步的。

最后,我无法同时配置同步和异步日志记录。请帮助和建议。

标签: asynchronousloggingsynchronizationlog4j2mixed

解决方案


我不确定你认为你在测试什么。

启用可加性后,日志事件将被复制并放置到 Disruptor 的 Ring Buffer 中,在那里它将被路由到不同线程上的控制台附加程序。将复制的事件放入缓冲区后,该事件将被传递到根记录器并在同一线程中路由到控制台 Appender。由于异步 Logger 和同步 Logger 都在做同样的事情,所以它们将花费大约相同的时间。所以我不太确定你为什么相信在 System.out 调用时会留下任何东西。

当您只使用异步记录器时,主线程除了将事件放入队列之外什么都不做,因此它会更快地响应,并且您的 System.out 消息很可能会在所有日志事件被写入之前出现。

我怀疑您忽略了一项非常重要的信息。当一个事件被路由到一个 Logger 时,在 LoggerConfig 上指定的与 Logger 关联的级别被检查。当可加性为真时,事件不会路由到父 Logger(没有一个)。它被路由到 LoggerConfig 的父 LoggerConfig。LoggerConfig 调用 isFiltered(event) 仅检查已在 LoggerConfig 上配置的过滤器。因此,即使您的 Root 记录器上有 level="info",仍然会记录通过 AsyncLogger 发送给它的调试事件。您必须将 ThresholdFilter 添加到 RootLogger 以防止这种情况。


推荐阅读