我使用Spring,并且在终止时我正在使用@PreDestroy来清理bean。我不明白为什么有时候随机记录成功,而其他人则失败。
// Using Log4j2
Logger log = LogManager.getLogger(MyClass.class);
@PreDestroy
public void close() {
log.warn("Test");
}
有时我什么也得不到(没有"测试"被记录),其他时候我会得到:
[13:48:44] INFO MyClass: Test
如果我在close()方法中包含System.out.println("Is this run?");
,它将始终打印。
我真的不确定发生了什么。我不知道是不是因为JVM正在关闭而且记录器被杀了......但我认为这会引发某种异常?
请注意,日志记录记录到文件+标准输出,我不知道这是否会影响任何内容。对于其他无数千行代码,日志记录工作正常,但不是这样。
注意:如果最终成为这个特定的库,我愿意切换日志库。
编辑:MyClass将是spring.xml文档中的bean。
答案 0 :(得分:4)
我认为归结为此,来自Runtime.addShutdownHook:
当虚拟机开始关闭序列时,它将以 某些未指定的顺序 启动所有已注册的关闭挂钩,并让它们同时运行。
因此,只要LogManager和Spring IOC容器都被JVM关闭挂钩关闭,就无法确保将记录消息。如果首先关闭LogManager,则消息将丢失。如果首先关闭IOC容器,则会记录该消息。
如果您在JEE容器中运行,则可能无法更改此内容。
但是,如果您在独立环境中运行,则可以向Log4j 2 shutdownHook="disable"
标记添加<configuration>
。这可以防止Log4j 2注册它自己的关闭钩子。然后,不是调用ctx.registerShutdownHook()
(建议关闭IOC的方法),而是注册自己的关闭挂钩。类似的东西:
class MyShutdownHook extends Thread {
private AbstractApplicationContext ctx;
public MyShutdownHook(AbstractApplicationContext ctx) {
this.ctx = ctx;
}
public void run() {
ctx.close();
Set<LoggerContext> contexts = new HashSet<>();
for (Logger logger : LoggerContext.getLoggers()) {
contexts.add(logger.getContext());
}
for (LoggerContext ctx : contexts) {
Configurator.shutdown(LogManager.getContext());
}
}
}
AbstractApplicationContext ctx = /* create context */
Runtime.getRunTime().addShutdownHook(new MyShutdownHook(ctx);
更新:更正了关闭Log4j2的过程 警告:我离开了我常用的构建机器,所以我没有编译它,但我相信它正在使用正确的API。
答案 1 :(得分:1)
我没有足够的声誉来添加评论,所以我会在这里回答:
根据JavaEE API javadoc:
检查是否在其他地方抛出异常&#34;静默&#34;,这可能是一个原因。
答案 2 :(得分:0)
与@Devon_C_Miller答案完全相同,但已更新以反映log4j2的最新版本
public class MonolithApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.refresh();
Runtime.getRuntime().addShutdownHook(new Log4j2AwareShutdownHook(context));
}
}
class Log4j2AwareShutdownHook extends Thread {
private AbstractApplicationContext ctx;
Log4j2AwareShutdownHook(AbstractApplicationContext ctx) {
this.ctx = ctx;
}
public void run() {
ctx.close();
LogManager.shutdown();
}
}
以及在log4j2配置中
<?xml version="1.0" encoding="UTF-8"?>
<Configuration shutdownHook="disable">
<Properties>
<Property name="LOG_EXCEPTION_CONVERSION_WORD">%xEx</Property>
<Property name="LOG_LEVEL_PATTERN">%5p</Property>
<Property name="LOG_DATEFORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property>
<Property name="CONSOLE_LOG_PATTERN">%d{${LOG_DATEFORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} %pid --- [%t] %-40.40c{1.} : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${sys:CONSOLE_LOG_PATTERN}"/>
</Console>
</Appenders>
<Loggers>
<Logger name="com.acme" level="debug"/>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>