如何刷新Log4J2中的异步记录器(带有disruptor)

时间:2015-05-19 21:42:58

标签: java asynchronous logging configuration log4j2

我使用Log4J2"使所有记录器异步"部分设置:

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

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

我处理了很多日志,然后在退出之前停止了appender:

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

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

但接下来会发生什么:

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

所以近距离看起来并没有实际冲洗,记录器最终失败了。

我的conf:

<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?

1 个答案:

答案 0 :(得分:4)

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

要彻底停止异步记录器,您可以致电org.apache.logging.log4j.core.async.AsyncLogger.stop()。这将阻塞,直到刷新所有消息。请注意:

  • 这仅适用于&#34;使所有记录器异步&#34;部分设置: -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
  • 您确定要测量吗?磁盘I / O将主导您的测量。如果要包含I / O,可以更简单地关闭异步日志记录并测量同步日志记录(包括I / O)。大多数人都对登录他们的应用程序的影响感兴趣,因此他们只测量对记录器的调用所花费的时间,并且不包括他们测量中的后台线程工作。