log4j2与java11兼容吗?
我试图在最新的Java11上运行我的项目。除了特定的文件记录器之外,其他一切都正常工作。日志记录在以前的Java版本(10、9、8)上运行良好,但在Java11上运行不好 在服务器运行期间,我只看到1条警告: 警告:不支持sun.reflect.Reflection.getCallerClass。这 将影响性能 以下是我的配置:log4j2与java11兼容吗?,java,log4j2,java-11,Java,Log4j2,Java 11,我试图在最新的Java11上运行我的项目。除了特定的文件记录器之外,其他一切都正常工作。日志记录在以前的Java版本(10、9、8)上运行良好,但在Java11上运行不好 在服务器运行期间,我只看到1条警告: 警告:不支持sun.reflect.Reflection.getCallerClass。这 将影响性能 以下是我的配置: <Configuration> <Appenders> <RollingFile name="postgres
<Configuration>
<Appenders>
<RollingFile name="postgresDBLog" fileName="${sys:logs.folder}/postgres.log"
filePattern="${sys:logs.folder}/archive/postgres.log.%d{yyyy-MM-dd}">
<PatternLayout>
<pattern>%d{HH:mm:ss.SSS} - %msg%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<RollingFile name="workersLog" fileName="${sys:logs.folder}/worker.log"
filePattern="${sys:logs.folder}/archive/worker.log.%d{yyyy-MM-dd}">
<PatternLayout>
<pattern>%d{HH:mm:ss.SSS} - %msg%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<RollingFile name="statsLog" fileName="${sys:logs.folder}/stats.log"
filePattern="${sys:logs.folder}/archive/stats.log.%d{yyyy-MM-dd}">
<PatternLayout>
<pattern>%msg%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
<RollingFile name="userLog" fileName="${sys:logs.folder}/blynk.log"
filePattern="${sys:logs.folder}/archive/blynk.log.%d{yyyy-MM-dd}">
<PatternLayout>
<pattern>%d{HH:mm:ss.SSS} %-5level- %msg%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="cc.blynk.server.workers" level="debug" additivity="false">
<appender-ref ref="workersLog"/>
</Logger>
<Logger name="cc.blynk.server.workers.StatsWorker" level="debug" additivity="false">
<appender-ref ref="statsLog"/>
</Logger>
<Logger name="cc.blynk.server.db" level="debug" additivity="false">
<appender-ref ref="postgresDBLog"/>
</Logger>
<Logger name="com.zaxxer.hikari" level="OFF" additivity="false">
</Logger>
<Logger name="org.asynchttpclient.netty.channel" level="OFF" additivity="false" />
<!-- turn off netty errors in debug mode for native library loading
https://github.com/blynkkk/blynk-server/issues/751 -->
<Logger name="io.netty" level="INFO" additivity="false" />
<Root>
<AppenderRef ref="userLog"/>
</Root>
</Loggers>
</Configuration>
更新:
将level=“info”
添加到根级别可以解决此问题
<Root level="info">
<AppenderRef ref="userLog"/>
</Root>
这一部分似乎不再适用于Java 11。如果您收到此消息,则您的应用程序未设置为使用多版本JAR。Log4j通过在位于META-INF/versions/9中的StackLocator版本中使用Stackwalker来支持Java 9+。根据应用程序的工作方式,您可能需要在jar清单中将Multi-Release设置为true。这对于Spring Boot jar是正确的。如果没有多版本支持,您将使用Java 9之前版本的StackLocator,它尝试使用Reflection.getCallerClass()。该类在Java9中被删除。Log4j将退回到一种较慢的方法来计算堆栈位置,但它仍然可以工作。因此出现了警告。如果有人在使用Maven,并且在组装扁平罐时遇到了相同的问题,下面是我为解决相同问题所做的:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>foo.bar.Generate</mainClass>
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
这一部分似乎不再适用于Java11
在从JDK 8升级到JDK 11之后,我遇到了同样的问题,即使用LoggerContext以编程方式更新日志级别设置。如果LogManager.getContext(boolean)
找不到LoggerContext,它将创建并返回一个新实例-更改该新对象将无效。指定Log4j的LogManager类的类加载器修复了本例中的问题:
LoggerContext ctx = (LoggerContext) LogManager.getContext(LogManager.class.getClassLoader(), false);
Log4J2当然是兼容的,它在中使用or 但是 1) 首先,当您像我一样使用slf4j接口时,您需要使用不同的Maven人工制品,请参见 2) 其次,当您像我一样创建一个包含所有依赖项的JAR时,您还需要添加多版本清单条目,请参见 或者在我的项目中搜索
<Multi-Release>true</Multi-Release>
true
此消息来自org/apache/logging/log4j/util/StackLocator.
它是log4j2 api.jar
的一部分(或log4j-api-2.x.y.jar
等)
你得到这个消息是因为一些聪明人决定从JRE中删除sun.reflect.Reflection.getCallerClass
(猜他们从Herostratus的书中删除了一页或其他内容)。这实际上发生在Openjdk11中
请注意,如果您有一个不太旧的log4j2 api.jar
,那么您不应该得到这个消息,因为这意味着它包含了另一个针对Java9+的此类实现(META-INF/versions/9/org/apache/logging/log4j/util/StackLocator.class
),而该类没有给出这个消息
但是,如果您使用一些帮助产品(TM),例如Spring Boot,它有自己的类加载器,它可能不兼容multi-relase jar,因此它会加载与Java8兼容的
StackLocator.class,而不是与Java9+兼容的,您仍然会收到此消息。您可以使用类名作为字符串来设置和更改日志级别,而不是使用class
public static MyLogger loggerFor(String name, String logLevel) {
Configurator.setRootLevel(Level.toLevel(logLevel, Level.INFO));
return new MyLogger(LogManager.getLogger(name));
}
您观察到从Java10到Java11的任何变化吗?看起来很奇怪。我没有改变任何东西,相同的jar,相同的环境,不同的JVM。可能是因为2.11.1
中的更改。您是否可以使用以前版本的log4j(2.11.0)和Java 11进行测试?@nullpointer在JDK 11(2.11.1和2.11.0)上运行我的应用程序时,我可以看到相同的警告。JDK10上没有警告。我的项目很大,所以很难创建一个可复制的示例。“似乎这部分不再适用于Java11。”-警告没有说它不起作用。它说它正在工作。。。慢慢来,谢谢。但是,多版本jar不是必须的。我不需要它,所以我不把它打包成多版本。为什么log4j2无法检查所需的类是否可用,如果可用则继续?依赖舱单有什么意义?这可能是错误的配置或误导。对我来说似乎是log4j2 bug。你说得对,这不是必须的。如果您不关心应用程序的性能会受到影响,并且可以接受警告,那么就没有问题。依赖清单的要点是,这是库支持Java9上多个Java版本的标准方式。如果你不喜欢它的工作方式,恐怕你得和OpenJDK的人谈谈。使用其他方法来确定要使用的正确实现可能会导致其他问题,因为在类路径上为多个java版本构建类可能会导致工具失败。对不起。我还是不明白这个问题。log4j2在运行时可以使用System.getProperty(“java.version”)。我错了吗?是的,你错了。StackWalker API只能使用Java 9+编译器进行编译,并且具有Java 9的类版本号。Log4j的其余部分是为Java7编译的。如果Java 9类与针对Java 7的类位于一起,那么许多工具在遇到该类时都会失败。当它们打包在多版本位置时不会失败,因为在Java9之前这是无效的。所以问题与检测版本无关。啊哈,所以log4j2被打包为multijar。。。这是个坏消息。也许为java7+和java9+提供不同的构建更好、更简单。只是想法,这是我的想法。在我的log4j2.xml
中有
。同样适用于我。使用Gradle,我将“Multi-Release”:true
添加到jar{manifest.attributes
。这修复了我的日志记录问题,但在AWS版本1 jars中与Jackson产生了许多其他问题。在尝试修复它几个小时后,我不得不回滚它。对于Gradle,我做了这个jar{
LoggerContext ctx = (LoggerContext) LogManager.getContext(LogManager.class.getClassLoader(), false);
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j18-impl</artifactId>
<version>2.12.1</version>
</dependency>
\- org.apache.logging.log4j:log4j-slf4j18-impl:jar:2.12.1:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.8.0-alpha2:compile
[INFO] +- org.apache.logging.log4j:log4j-api:jar:2.12.1:compile
[INFO] \- org.apache.logging.log4j:log4j-core:jar:2.12.1:runtime
<Multi-Release>true</Multi-Release>
public static MyLogger loggerFor(String name, String logLevel) {
Configurator.setRootLevel(Level.toLevel(logLevel, Level.INFO));
return new MyLogger(LogManager.getLogger(name));
}