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

标签 java asynchronous logging configuration log4j2

我通过设置使用 Log4J2“使所有记录器异步”部分:

-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

所以关闭看起来并不像它实际上正在刷新,记录器最终失败了。

我的 session :

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

Log4j 2.5 之前的版本

要完全停止异步记录器,您可以调用 org.apache.logging.log4j.core.async.AsyncLogger.stop()

Log4j 2.5 及更高版本

要干净地停止异步记录器,获取对其 LoggerContext 的引用并停止它:

void stopAsyncLogger() {
    // you might need different arguments to getContext() to find the right one
    LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
    ctx.stop();
}

对于所有版本,这会阻塞,直到所有消息都被刷新。注意:

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

关于java - 如何刷新 Log4J2 中的异步记录器(使用中断器),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30336669/

相关文章:

javascript - 我正在尝试用JS编写一个简单的异步代码,但它似乎不起作用

java - 在 HttpClient 中开启日志记录

ios - 在 iOS 上拦截崩溃

Java 性能不一致

java - 在类里面找不到符号

java - 文件存在()返回False;当它执行Android内部存储时

javascript - 在 setTimeout 中将多个参数传递给 promise 解析

java - Android 日期格式 : How to convert date in alphabets

javascript - RequireJS 异步加载导致用户体验(UX)不佳?

java - "WARN No appenders could be found for logger"甚至记录器正在记录内容