带有 Log4j2 的 Weblogic 12c 在 stop/start 后停止记录

Weblogic 12c with Log4j2 stops logging after stop/start

当我们在 Weblogic 12c 中停止 war 然后再次启动它时,我遇到了一个奇怪的行为。由于某种超出我理解的原因,Log4j2 停止写入日志。它会创建一个新的日志文件,但不会写入任何条目。

我已经调试并看到 Log4jServletContainerInitializer 和 Log4jServletContextListener 被调用,就像它们在安装 war 时一样。我没有注意到任何差异(不幸的是,这只是对我注意力持续时间的测试)。

那么,对于 Weblogic 12c 中的 Log4J2,安装和启动之间可能有什么不同,以及可能在哪里查找错误,您是否知道?

您的问题:

出于某种超出我理解的原因,Log4j2 停止写入日志。它会创建一个新的日志文件,但不会写入任何条目。


根本原因分析:

有些问题确实会发生。

  1. 如果您的 log4j 配置不正确 log4j.properties 文件。
  2. 如果您的追加属性未变为真。
  3. 如果您使用两个记录器,如 Log4JJUL,它们使用相同的 应用程序(标准输出)。
  4. 如果您的 log4j jar 文件没有正确设置到您的类路径。

解决方案:

答案 1: 在您的类路径中,有一个库设置可以拦截 Log4J 调用并将它们转换为 JUL 调用。那么它可能会导致这个问题。因此,请正确指定实际需要导入的内容。 java.util.logging.Loggerorg.apache.log4j.Logger

答案 2: 属性为 case sensitive。所以你的file name would be same with appender。并且不要忘记将 appender 设置为 true。

log4j.appender.mainAppender.File=yourLogFile.log
log4j.appender.mainAppender.Append=true

答案 3: 特别是对于 Hibernate,包括 slf4j 以确保所有记录器与其合作。


答案4: tomcat 有时会出现此问题。如果 tomcat 安全启用,并且策略文件中缺少多个权限,则会出现此类问题。给权限后就可以正常使用了


Log4J 实际上做了什么?

Log4J 只会打印 info 及以上的消息,并且会将它们打印到控制台和文件中。您可以通过在 log4j.rootLogger 中将 INFO 更改为 ALL 来更改此行为。如果这不起作用,请将 -Dlog4j.debug=true 添加到您的 JVM 参数 - 这将使 Log4J 发出关于自身的调试消息(到 System.out),这样您就可以看到发生了什么。 感谢@Isaac

资源Link:

  1. Log4J creates log file but does not write to it
  2. Issue with log4j log not writing to file

UPDATE for log4j2:


非常感谢 rgoers 指出 log4j2 的问题。我正在更新。

来自 wilkinsona 的 P.O.V 的根本原因分析

当触发 restart 时,DevTools 运行s 然后清除所有已注册的关闭挂钩。一种这样的钩子是 Log4J2 的 DefaultShutdownCallbackRegistry。 Log4jContextFactory 维护对 DefaultShutdownCallbackRegistry 的引用,而 LogManager 持有对 Log4jContextFactory 的静态引用。 Log4J2's classes are loaded by the app classloader which means that there's a single LogManager, Log4jContextFactory, and DefaultShutdownCallbackRegistry shared across restarts.

DefaultShutdownCallbackRegistry 是 运行 作为重新启动的一部分时,它会停止 LoggerContext 并将自己的状态设置为 STOPPED。随着重新启动的进行,将创建一个新的 LoggerContext 并尝试在注册表中为其注册一个关闭回调。这失败了,因为注册表的状态仍然是 STOPPED.

解决方案:

Wilkinsona 提供了一种 hack 方法来解决这个问题。这在下面给出。努力应对。

在 Restarter 运行JVM 的关闭挂钩之前清除注册表中的回调更好。它可以防止异常发生,并且 日志记录在重新启动后继续工作。

private void prepareLog4J2ForRestart() throws Exception {
    if (ClassUtils.isPresent("org.apache.logging.log4j.LogManager",
            getClass().getClassLoader())) {
        LoggerContextFactory factory = LogManager.getFactory();
        Field field = ReflectionUtils.findField(factory.getClass(),
                "shutdownCallbackRegistry");
        ReflectionUtils.makeAccessible(field);
        ShutdownCallbackRegistry shutdownCallbackRegistry = (ShutdownCallbackRegistry) ReflectionUtils
                .getField(field, factory);
        Field hooksField = ReflectionUtils
                .findField(shutdownCallbackRegistry.getClass(), "hooks");
        ReflectionUtils.makeAccessible(hooksField);
        @SuppressWarnings("unchecked")
        Collection<Cancellable> state = (Collection<Cancellable>) ReflectionUtils
                .getField(hooksField, shutdownCallbackRegistry);
        state.clear();
    }
}

资源Link:

  1. Log4j 2.4 breaks rc1 devtools
  2. Call context.close() rather than shutdown hook in DevTools restart

更新 2:

What kind of listener to add to my JEE application, to get the expected behaviour?

监听器的编写,可以按照教程进行

  1. ServletContextListener Example
  2. Writing a Listener Class
  3. Servlet 侦听器示例 – ServletContextListener, HttpSessionListener 和 ServletRequestListener