Is log4j2 compatible with Java 11?
I tried to run my project on the latest Java 11. Everything works, except the specific file logger. Logging works fine on previous Java versions - 10, 9, 8, but not on Java 11.
During server run I see only 1 warning:
WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.
Here is my configuration:
<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>
All loggers, except userLog
works fine. However, userLog
is empty.
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)
Update:
Adding level="info"
to the root level fixes the issue.
<Root level="info">
<AppenderRef ref="userLog"/>
</Root>
However, in my project I was using a code that was setting a log level based on properties file. Here is a code:
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);
}
Seems like this part is no longer work with Java 11.
Solution 1:
If someone is using Maven and is having the same issue while assembling a flat jar, here is what I did to fix the same issue:
<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>
The important part is <Multi-Release>true</Multi-Release>
.
Note that the Java code I'm using now to change loggers level is:
Configurator.setAllLevels("foo.bar", Level.DEBUG);
Solution 2:
Log4J2 is of course compatible it uses the JDK Multi-Release feature or in more detail.
BUT...
1) First, when you are using - like me - the slf4j interface, you need to use a different Maven artefact, see 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>
which adds all dependencies as 'mvn dependency:tree' reveals:
\- 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) And second, when you are creating - like me - one single JAR, which includes all dependencies, you need to add the Multi-Release manifest entry as well, see https://issues.apache.org/jira/browse/LOG4J2-2537 or in my project's pom.xml and search for
<Multi-Release>true</Multi-Release>
Solution 3:
If you are getting this message then your application is not setup to use multi-release jars. Log4j supports Java 9+ by using Stackwalker in a version of StackLocator that is located in META-INF/versions/9. Depending on how your application works, you may need to have Multi-Release set to true in the jar manifest. This is true for Spring Boot jars. Without multi-release support you will use the pre-Java 9 version of StackLocator which tries to use Reflection.getCallerClass(). That class was removed in Java 9. Log4j will fall back to a slower way to calculate stack locations but it will still work. Hence the warning.