我正在尝试将我的 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/