如何正确关闭log4j2

13
如果Log4j2不在Web应用程序中运行,正确的关闭方式是什么?我只看到了一个无操作(noop)的LogManager.shutdown()。
3个回答

18

目前没有公开的API,但您可以使用

((LifeCycle) LogManager.getContext()).stop();
如果您对此有公共API的兴趣,请在此处进行投票或添加评论:https://issues.apache.org/jira/browse/LOG4J2-124
更新:
在Log4j 2.5中,您可以调用Configurator.shutdown()。在Log4j 2.6中,您可以调用LogManager.shutdown()

1
你应该在log4j2.xml中添加shutdownHook="disable"来禁用自动关闭挂钩。 - jansohn

9

Log4j-Web库是在Web应用程序中正确清理资源的首选方法。

要启用它,请将此依赖项添加到您的pom.xml文件中。

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-web</artifactId>
    <version>${log4j2.version}</version>
    <scope>runtime</scope>
</dependency>

它将在Servlet 3.*环境中“开箱即用”。 如果您使用较旧的Servlet规范,请参阅此处有关如何启用log4j2的适当清理的详细信息: https://logging.apache.org/log4j/2.x/manual/webapp.html


请注意,此问题特别涉及“不在Web应用程序内运行”的情况[强调是我的]。 - ruakh
你是对的 @ruakh 无论如何,我还是将答案留在这里,因为有些人认为它对他们的情况有用... - leokom

9

解释和故事背景

Log4j 2 内部使用的是他们称之为 ShutdownRegistrationStrategy 的东西。它由一个类组成,该类注册一个或多个关机回调函数,在适当的时间调用这些回调函数。他们提供了一个名为 ShutdownCallbackRegistry 的接口和默认实现 DefaultShutdownCallbackRegistry。此实现将自身注册为 JVM 的关机挂钩,使用 Runtime.getRuntime().addShutdownHook()

根据 Log4j 2 bug 跟踪器上的一些问题(LOG4J2-868LOG4J2-658),正确的方法是提供你自己的 ShutdownCallbackRegistry 接口实现。由于没有公共 API 关闭 Log4j 2,这是唯一真正有效的方法。

提议的解决方案

所以,我为了解决这个问题,实现了自己版本的 ShutdownCallbackRegistry 接口。它大多数情况下与默认实现做的事情相同,但是不会将自身注册为关机挂钩,而是等待手动调用。这在内部通过将对象实例保存在静态字段中实现。然后,您只需要调用单个静态方法来启动关机过程,因此我将其命名为 StaticShutdownCallbackRegistry

您可以在 GitHub/DjDCH/Log4j-StaticShutdown 找到完整的解决方案和说明,并在您自己的项目中使用它。基本上,在您的应用程序中只需执行以下操作:

StaticShutdownCallbackRegistry.invoke();

我不能毫无疑问地说这是完美的解决方案,也不能保证我的实现是完美的,但我尽力按照正确的方式去做(根据关于此事并不存在的文档)。如果您认为这个解决方案合适,请告诉我您的反馈。


1
看起来版本2.6重新添加了一个适当的手动.shutdown,有人可以确认吗?但在这里它并没有真正起作用。 - Andrea Richiardi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接