如何刷新 Log4J2 中的异步记录器(使用中断器)

How to flush Asynchronous loggers in Log4J2 (with disruptor)

我通过设置使用 Log4J2 "Making All Loggers Asynchronous" 部分:

-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector.

https://logging.apache.org/log4j/2.x/manual/async.html

我处理了很多日志,然后在退出前停止了附加程序:

org.apache.logging.log4j.core.Logger coreLogger = (org.apache.logging.log4j.core.Logger) logger;
org.apache.logging.log4j.core.LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) coreLogger.getContext();
Map<String, Appender> appenders = context.getConfiguration().getAppenders();
for (Appender appender : appenders.values()) {
  appender.stop();
}

通过这样做,我希望它会在我退出程序之前刷新异步附加程序并将剩余的日志写入磁盘。

但事情是这样的:

2015-05-19 14:09:58,540 ERROR Attempted to append to non-started appender myFileAppender
Exception in thread "AsyncLogger-1" java.lang.RuntimeException: org.apache.logging.log4j.core.appender.AppenderLoggingException: Attempted to append to non-started appender myFileAppender
    at com.lmax.disruptor.FatalExceptionHandler.handleEventException(FatalExceptionHandler.java:45)
    at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:147)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.logging.log4j.core.appender.AppenderLoggingException: Attempted to append to non-started appender myFileAppender
    at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:89)
    at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:430)
    at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:409)
    at org.apache.logging.log4j.core.Logger$PrivateConfig.logEvent(Logger.java:288)
    at org.apache.logging.log4j.core.async.AsyncLogger.actualAsyncLog(AsyncLogger.java:305)
    at org.apache.logging.log4j.core.async.RingBufferLogEvent.execute(RingBufferLogEvent.java:100)
    at org.apache.logging.log4j.core.async.RingBufferLogEventHandler.onEvent(RingBufferLogEventHandler.java:43)
    at org.apache.logging.log4j.core.async.RingBufferLogEventHandler.onEvent(RingBufferLogEventHandler.java:28)
    at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:128)
    ... 3 more

所以关闭看起来不像是在刷新,记录器最终失败了。

我的会议:[​​=15=]

<Configuration>
  <Appenders>
    <RollingFile name="myFileAppender" fileName="/tmp/test.log" ignoreExceptions="false" immediateFlush="false">
      <PatternLayout><Pattern>%m%n</Pattern></PatternLayout>
      <Policies>
        <TimeBasedTriggeringPolicy />
      </Policies>
    </RollingFile>
    <Console name="STDOUT">
      <PatternLayout pattern="%C{1.} %m %level MDC%X%n"/>
    </Console>
  </Appenders>

  <Loggers>
    <Logger name="myLogger" level="info" additivity="false">
      <AppenderRef ref="myFileAppender" />
    </Logger>
    <Root level="fatal">
      <AppenderRef ref="STDOUT"/>
    </Root>
  </Loggers>
</Configuration>

如何刷新/同步 log4j2?

Log4j2 有一个关闭挂钩(用于非 Web 应用程序),负责等待后台线程处理仍在队列中的任何事件。所以最好的办法是在 appender 仍在使用时不要停止它们。让 log4j2 负责清理工作。

要干净地停止异步记录器,您可以调用 org.apache.logging.log4j.core.async.AsyncLogger.stop()。这会阻塞,直到所有消息都被刷新。注意:

  • 这仅在 "Making All Loggers Asynchronous" 部分通过设置时有效: -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector.
  • 你确定要测量这个吗?磁盘 I/O 将主导您的测量。如果要包含 I/O,关闭异步日志记录并测量同步日志记录(包括 I/O)可能会更简单。大多数人都对日志记录对其应用程序的影响很感兴趣,因此他们只测量对记录器的调用所花费的时间,并且不将后台线程工作包括在他们的测量中。