Java Util Logging 重定向到 Log4j2 不适用于 Spring Boot 应用程序

标签 java spring spring-boot

我正在尝试将我的 Spring Boot 应用程序中的所有日志记录框架重定向到 Log4j2。它适用于 Java Commons Logging、SLF4J 和 Log4j 1.x。 不幸的是,Java Util Logging (JUL) 重定向不起作用,因为 java.util.logging.Logger在应用程序类路径尚未完全组装时由 Plexus 启动器使用。

Log4j2 文档要求设置 VM 参数 -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager或调用 System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager")使重定向工作的方法。它们都不起作用:

  • System.setProperty()在我的应用程序代码中来得太晚了。一些启动代码已经对 LogManager 进行了一些调用或 Logger以便无法再安装 Redirection-LogManager。
  • VM 参数也不起作用,因为在

调用System.setProperty()被忽略,因为 Java Util Logging 框架已经初始化。使用 VM 参数会发生以下异常:

$ mvn spring-boot:run -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager

Could not load Logmanager "org.apache.logging.log4j.jul.LogManager"
java.lang.ClassNotFoundException: org.apache.logging.log4j.jul.LogManager
    at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:50)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:247)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239)
    at java.util.logging.LogManager$1.run(LogManager.java:195)
    at java.util.logging.LogManager$1.run(LogManager.java:181)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.util.logging.LogManager.<clinit>(LogManager.java:181)
    at java.util.logging.Logger.demandLogger(Logger.java:448)
    at java.util.logging.Logger.getLogger(Logger.java:502)
    at com.google.inject.internal.util.Stopwatch.<clinit>(Stopwatch.java:27)
    at com.google.inject.internal.InternalInjectorCreator.<init>(InternalInjectorCreator.java:61)
    at com.google.inject.Guice.createInjector(Guice.java:96)
    at com.google.inject.Guice.createInjector(Guice.java:73)
    at com.google.inject.Guice.createInjector(Guice.java:62)
    at org.codehaus.plexus.DefaultPlexusContainer.addPlexusInjector(DefaultPlexusContainer.java:481)
    at org.codehaus.plexus.DefaultPlexusContainer.<init>(DefaultPlexusContainer.java:206)
    at org.apache.maven.cli.MavenCli.container(MavenCli.java:542)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:279)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:197)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)

深入研究代码表明初始化是由内部使用 JUL 的 Guice 库引起的。在这种情况下,它只是对 com.google.inject.internal.util.Stopwatch.<clinit>(Stopwatch.java:27) 的调用。 .

所以问题是,有人知道如何解决这个问题吗?

2015-08-23 更新: 下面的建议是添加配置属性 <fork>true</fork>用于通过 Spring boot Maven 插件运行应用程序 mvn spring-boot:run .

不幸的是,它在通过命令行运行应用程序时不起作用 java -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager -jar myapp.jar .在这种情况下会发生以下异常:

Could not load Logmanager "org.apache.logging.log4j.jul.LogManager"
java.lang.ClassNotFoundException: org.apache.logging.log4j.jul.LogManager
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.util.logging.LogManager$1.run(LogManager.java:195)
    at java.util.logging.LogManager$1.run(LogManager.java:181)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.util.logging.LogManager.<clinit>(LogManager.java:181)
    at java.util.logging.Logger.demandLogger(Logger.java:448)
    at java.util.logging.Logger.getLogger(Logger.java:502)
    at org.springframework.boot.loader.Launcher.<init>(Launcher.java:43)
    at org.springframework.boot.loader.ExecutableArchiveLauncher.<init>(ExecutableArchiveLauncher.java:48)
    at org.springframework.boot.loader.ExecutableArchiveLauncher.<init>(ExecutableArchiveLauncher.java:45)
    at org.springframework.boot.loader.JarLauncher.<init>(JarLauncher.java:30)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:45)

因此,不幸的是,Spring Boot Launcher 也使用了 Java Util Logging,从而阻止了使用 Log4j2 的 JUL 重定向。

我查看了类的源代码 org.springframework.boot.loader.Launcher及其子类。问题是由 Launcher 中静态记录器变量的声明引起的类(class)。这个记录器似乎没有被任何 Launcher 类使用,所以它很容易被删除。 问题是是否可以完全删除对 JUL 的依赖以修复 JUL 重定向问题?也许通过使用 stderr 而不是 JUL 来进行 Launcher 诊断?

最佳答案

您当前的方法意味着 Maven 和您的应用程序都将尝试使用自定义日志管理器。 Maven 尝试使用它会导致您看到的异常。

您可以在 pom.xml 中配置 Spring Boot 的 Maven 插件,为您的应用程序派生一个单独的 JVM:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
      <fork>true</fork>
    </configuration>
  </plugin>

然后在应用程序的主要方法中使用 System.setProperty。 fork 一个单独的 JVM 将防止 Maven 自己的日志记录在您的配置生效之前搞砸。

关于Java Util Logging 重定向到 Log4j2 不适用于 Spring Boot 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32161616/

相关文章:

java - 由 : org. hibernate.MappingException 引起:属性映射的列数错误:

java - AbstractList.add() 不支持的操作

java - 何时使用 LinkedListNode 与 LinkedList

java - Apache ActiveMQ 回退机制

spring - application.yml 中的环境变量不适用于以空格开头的默认值

java - 如何在 Spring Boot 中记录 Rest Web 服务所花费的时间?

java - jTable 将数据输入到列中

java - 列出 Red5 可用的流

spring - 什么决定了 hibernate session 在 @Transactional 之外是否可用

java - 为什么我不能直接在测试中 @Autowired 我的服务以及为什么我需要 @Autowired 存储库?