混合同步/异步日志记录 log4j 不起作用

时间:2021-04-26 18:00:35

标签: asynchronous logging synchronization log4j2 mixed

我正在尝试分析和实现混合同步和异步日志记录。我正在使用 Spring 启动应用程序和干扰器 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 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”,那么所有日志都是异步的。

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

1 个答案:

答案 0 :(得分:0)

我不确定您认为自己在测试什么。

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

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

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