混合 sync/async 日志记录 log4j 不起作用

mixed sync/async logging log4j does not work

我正在尝试分析和实施混合同步和异步日志记录。我正在使用 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>

演示 class 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",那么我可以看到我预期的上述结果。现在我有第二个演示 class:

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));     
 }

}

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

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

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

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

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

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