【问题标题】:Do I need to flush events when shutting down using logback?使用 logback 关闭时是否需要刷新事件?
【发布时间】:2011-04-10 09:00:58
【问题描述】:

我们正在为几个 Web 应用程序从 log4j 迁移到 logback。在关闭我们的应用程序时,我们当前调用:

org.apache.log4j.LogManager.shutdown();

这应该刷新所有异步日志记录并关闭所有外部资源(文件、套接字)。

logback 中是否有类似的东西,或者它是否会在关机时自动刷新?

迈克

【问题讨论】:

  • 有趣的问题——我从来没有真正想过这个问题。由于您必须显式配置 log4j 以缓冲输出,因此我假设可能只需要在这种情况下调用关闭。不过,我相信 slf4j 默认会缓冲。
  • logback 在每条日志语句之后刷新,所以除非你在做一些时髦的事情,否则不需要显式的 stop() 调用。
  • @DavidRoussel 这句话让我看了Logback Appenders。确实:默认情况下,每个日志事件都会立即刷新到底层输出流。这种默认方法更安全,因为如果您的应用程序在没有正确关闭附加程序的情况下退出,日志事件不会丢失。但是,为了显着提高日志记录吞吐量,您可能需要将底层编码器的 immediateFlush 属性设置为 false 。编码器,特别是 LayoutWrappingEncoder 将在单独的章节中描述。​​
  • @DavidTonhofer 将 immediateFlush 设置为 false 的问题在于,它仅在缓冲区已满时才刷新。因此,如果您跟踪日志文件,则可能在您的应用程序中发生了一个操作,但您可能不会在日志中看到它,因为它位于等待刷新的缓冲区中。出于这个原因,我更喜欢使用 AsyncAppender。理想情况下,当没有更多异步日志事件挂起时,将有某种方法可以使用 AsyncAppender 和 immediateFlush=false 并刷新。但这没有实现。

标签: java logback


【解决方案1】:

似乎只是将<shutdownHook/> 添加到配置中应该会停止上下文。

来自logback docs

<configuration>
   <!-- in the absence of the class attribute, assume 
   ch.qos.logback.core.hook.DelayingShutdownHook -->
   <shutdownHook/>
  .... 
</configuration>

来自DelayingShutdownHook summary

ShutdownHook 实现在指定延迟后停止 Logback 上下文。默认延迟为 0 毫秒(零)。

【讨论】:

  • 这种方法的问题(零延迟)是其他关闭挂钩完成的任何日志记录都将丢失,因为 logback 将在它们完成之前关闭。您可以指定一个非零延迟,但这实际上会阻止您的 JVM 终止,直到该延迟结束。例如如果我认为我的其他关闭挂钩将在 45 秒内完成,那么我可以将 logback 关闭挂钩延迟设置为 60 秒,但我的 JVM 将始终需要 60 秒才能关闭。
【解决方案2】:

这是一个简单的方法:

import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.LoggerContext;

...

ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
// Check for logback implementation of slf4j
if (loggerFactory instanceof LoggerContext) {
    LoggerContext context = (LoggerContext) loggerFactory;
    context.stop();
}

【讨论】:

    【解决方案3】:

    我不知道像 log4j 那样的整体管理器关闭,但是当我使用 ServletContextListener 销毁它们的上下文时,我会关闭所有单独的上下文记录器,如下所示:

    ContextSelector selector = StaticLoggerBinder.getSingleton().getContextSelector();
    LoggerContext context = selector.detachLoggerContext(contextName);
    if (context != null) {
        Logger logger = context.getLogger(Logger.ROOT_LOGGER_NAME);
        context.reset();
    } else {
        System.err.printf("No context named %s was found", contextName);
    }
    

    另外,LoggerContext.stop() 是可用的,并且在内部执行一些相同的功能,但我不使用它,所以我无法评论它是否比重置更好。

    【讨论】:

      【解决方案4】:

      从 1.1.10 版开始,logback 负责在 web 应用停止或重新加载时停止当前的 logback-classic 上下文。

      这是更新后的文档:https://logback.qos.ch/manual/configuration.html#webShutdownHook

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-30
        • 1970-01-01
        • 1970-01-01
        • 2018-07-15
        相关资源
        最近更新 更多