log4j2 与 Java 11 兼容吗?
Is log4j2 compatible with Java 11?
我试图 运行 我的项目在最新的 Java 11 上。一切正常,除了特定的文件记录器。日志记录在以前的 Java 版本 - 10、9、8 上工作正常,但在 Java 11.
上不行
在服务器 运行 期间我只看到 1 个警告:
WARNING: sun.reflect.Reflection.getCallerClass is not supported. This
will impact performance.
这是我的配置:
<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>
所有记录器,除了 userLog
工作正常。但是,userLog
是空的。
log4j2 version 2.11.1
Ubuntu 16.04.5 LTS
java version "11.0.1" 2018-10-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode)
更新:
将 level="info"
添加到根级别可解决此问题。
<Root level="info">
<AppenderRef ref="userLog"/>
</Root>
但是,在我的项目中,我使用的是基于属性文件设置日志级别的代码。这是一个代码:
private static void changeLogLevel(String level) {
Level newLevel = Level.valueOf(level);
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration conf = ctx.getConfiguration();
conf.getLoggerConfig(LogManager.ROOT_LOGGER_NAME).setLevel(newLevel);
ctx.updateLoggers(conf);
}
这部分似乎不再适用于 Java 11.
如果您收到此消息,则说明您的应用程序未设置为使用多版本 jar。 Log4j 通过在位于 META-INF/versions/9 的 StackLocator 版本中使用 Stackwalker 来支持 Java 9+。根据您的应用程序的工作方式,您可能需要在 jar 清单中将 Multi-Release 设置为 true。 Spring 引导罐也是如此。如果没有多版本支持,您将使用 Java 9 之前的 StackLocator 版本,它会尝试使用 Reflection.getCallerClass()。 class 已在 Java 9 中删除。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>
重要的部分是<Multi-Release>true</Multi-Release>
。
请注意,我现在用来更改记录器级别的 Java 代码是:
Configurator.setAllLevels("foo.bar", Level.DEBUG);
Seems like this part is no longer work with Java 11.
我 运行 在从 JDK 8 升级到 JDK 11 后使用 LoggerContext 以编程方式更新 LogLevel 设置时遇到了同样的问题。如果 LogManager.getContext(boolean)
不能找到它将创建的 LoggerContext 和 return 一个新实例 - 更改该新对象将无效。指定 Log4j 的 LogManager 的 classloader class 解决了我们案例中的问题:
LoggerContext ctx = (LoggerContext) LogManager.getContext(LogManager.class.getClassLoader(), false);
Log4J2 当然兼容它使用 JDK Multi-Release feature or in more detail.
但是...
1) 首先,当您像我一样使用 slf4j 接口时,您需要使用不同的 Maven 工件,请参阅 http://logging.apache.org/log4j/2.x/log4j-slf4j-impl/index.html
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j18-impl</artifactId>
<version>2.12.1</version>
</dependency>
添加所有依赖项,如 'mvn dependency:tree' 所示:
\- 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
2) 其次,当您像我一样创建一个包含所有依赖项的 JAR 时,您还需要添加多版本清单条目,请参阅 https://issues.apache.org/jira/browse/LOG4J2-2537
或者在我的项目 pom.xml 中搜索
<Multi-Release>true</Multi-Release>
此消息来自 org/apache/logging/log4j/util/StackLocator.<classconstructor>
,它是 log4j2-api.jar
(或 log4j-api-2.x.y.jar
等)的一部分。
您收到此消息是因为一些聪明人决定 sun.reflect.Reflection.getCallerClass
必须从 JRE 中删除(我猜他们从 Herostratus 的书中摘录了一页或其他内容)。这实际上发生在 Openjdk11.
请注意,如果您的 log4j2-api.jar
版本不太旧,则不应收到此消息,因为它是一个 multi-release-jar,意味着它包含此 [= 的另一个实现29=] for Java9+ (META-INF/versions/9/org/apache/logging/log4j/util/StackLocator.class
) 不给出此消息。
但是,如果您使用一些 Helping Product(TM),例如 Spring Boot,它有自己的 classloader,它可能不兼容 multi-relase-jar,所以它加载 Java8 兼容 StackLocator.class
而不是 Java9+ 兼容,你仍然会收到此消息。
我试图 运行 我的项目在最新的 Java 11 上。一切正常,除了特定的文件记录器。日志记录在以前的 Java 版本 - 10、9、8 上工作正常,但在 Java 11.
上不行在服务器 运行 期间我只看到 1 个警告:
WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.
这是我的配置:
<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>
所有记录器,除了 userLog
工作正常。但是,userLog
是空的。
log4j2 version 2.11.1
Ubuntu 16.04.5 LTS
java version "11.0.1" 2018-10-16 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.1+13-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.1+13-LTS, mixed mode)
更新:
将 level="info"
添加到根级别可解决此问题。
<Root level="info">
<AppenderRef ref="userLog"/>
</Root>
但是,在我的项目中,我使用的是基于属性文件设置日志级别的代码。这是一个代码:
private static void changeLogLevel(String level) {
Level newLevel = Level.valueOf(level);
LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
Configuration conf = ctx.getConfiguration();
conf.getLoggerConfig(LogManager.ROOT_LOGGER_NAME).setLevel(newLevel);
ctx.updateLoggers(conf);
}
这部分似乎不再适用于 Java 11.
如果您收到此消息,则说明您的应用程序未设置为使用多版本 jar。 Log4j 通过在位于 META-INF/versions/9 的 StackLocator 版本中使用 Stackwalker 来支持 Java 9+。根据您的应用程序的工作方式,您可能需要在 jar 清单中将 Multi-Release 设置为 true。 Spring 引导罐也是如此。如果没有多版本支持,您将使用 Java 9 之前的 StackLocator 版本,它会尝试使用 Reflection.getCallerClass()。 class 已在 Java 9 中删除。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>
重要的部分是<Multi-Release>true</Multi-Release>
。
请注意,我现在用来更改记录器级别的 Java 代码是:
Configurator.setAllLevels("foo.bar", Level.DEBUG);
Seems like this part is no longer work with Java 11.
我 运行 在从 JDK 8 升级到 JDK 11 后使用 LoggerContext 以编程方式更新 LogLevel 设置时遇到了同样的问题。如果 LogManager.getContext(boolean)
不能找到它将创建的 LoggerContext 和 return 一个新实例 - 更改该新对象将无效。指定 Log4j 的 LogManager 的 classloader class 解决了我们案例中的问题:
LoggerContext ctx = (LoggerContext) LogManager.getContext(LogManager.class.getClassLoader(), false);
Log4J2 当然兼容它使用 JDK Multi-Release feature or in more detail.
但是...
1) 首先,当您像我一样使用 slf4j 接口时,您需要使用不同的 Maven 工件,请参阅 http://logging.apache.org/log4j/2.x/log4j-slf4j-impl/index.html
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j18-impl</artifactId>
<version>2.12.1</version>
</dependency>
添加所有依赖项,如 'mvn dependency:tree' 所示:
\- 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
2) 其次,当您像我一样创建一个包含所有依赖项的 JAR 时,您还需要添加多版本清单条目,请参阅 https://issues.apache.org/jira/browse/LOG4J2-2537 或者在我的项目 pom.xml 中搜索
<Multi-Release>true</Multi-Release>
此消息来自 org/apache/logging/log4j/util/StackLocator.<classconstructor>
,它是 log4j2-api.jar
(或 log4j-api-2.x.y.jar
等)的一部分。
您收到此消息是因为一些聪明人决定 sun.reflect.Reflection.getCallerClass
必须从 JRE 中删除(我猜他们从 Herostratus 的书中摘录了一页或其他内容)。这实际上发生在 Openjdk11.
请注意,如果您的 log4j2-api.jar
版本不太旧,则不应收到此消息,因为它是一个 multi-release-jar,意味着它包含此 [= 的另一个实现29=] for Java9+ (META-INF/versions/9/org/apache/logging/log4j/util/StackLocator.class
) 不给出此消息。
但是,如果您使用一些 Helping Product(TM),例如 Spring Boot,它有自己的 classloader,它可能不兼容 multi-relase-jar,所以它加载 Java8 兼容 StackLocator.class
而不是 Java9+ 兼容,你仍然会收到此消息。