I add an appender programmatically. It was working until I added maven-shade-plugin
. I wonder what makes my appender fail.
The appender works ✅ or not ❌ in these scenarios:
mvn clean compile
mkdir -p local/log4j-jars
unzip $HOME/.m2/repository/org/apache/logging/log4j/log4j-api/2.17.2/log4j-api-2.17.2.jar -d local/log4j-jars
unzip -o $HOME/.m2/repository/org/apache/logging/log4j/log4j-core/2.17.2/log4j-core-2.17.2.jar -d local/log4j-jars
cd local/log4j-jars
zip -r ../log4j-jars.zip .
cd ../..
# Scenario 2 ❌ uses fat jar
java -cp "target/log4j-test-1.0-SNAPSHOT.jar" org.example.Main
# Scenario 3 ✅ uses separate jars
java -cp "target/original-log4j-test-1.0-SNAPSHOT.jar:$HOME/.m2/repository/org/apache/logging/log4j/log4j-core/2.17.2/log4j-core-2.17.2.jar:$HOME/.m2/repository/org/apache/logging/log4j/log4j-api/2.17.2/log4j-api-2.17.2.jar" org.example.Main
# Scenario 4 ❌ uses log4j files unzipped
java -cp "target/original-log4j-test-1.0-SNAPSHOT.jar:local/log4j-jars" org.example.Main
# Scenario 5 ✅ uses log4j files re-zipped
java -cp "target/original-log4j-test-1.0-SNAPSHOT.jar:local/log4j-jars.zip" org.example.Main
In the scenario 5, I have noticed that I can remove some files in META-INF
, but for my appender to work, I need to keep the following:
META-INF
org
(contains Log4j2Plugins.dat
)services
(without this, the app even crashes)versions
MANIFES.MF
Log4j2Plugins.dat
, but in my project there's only one file, in log4j2-core
.META-INF
folder is not processed like in a jar)The problem with maven-shade-plugin
is that it breaks the manifest of the original jars and overwrites important resources. I find the spring-boot-maven-plugin
much more useful and it can be also used by applications that don't use Spring at all.
The maven-shade-plugin
in the context of Log4j requires a minimal configuration as in this question:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-transform-maven-shade-plugin-extensions</artifactId>
<version>0.1.0</version>
</dependency>
</dependencies>
<configuration>
<transformers>
<transformer implementation="org.apache.logging.log4j.maven.plugins.shade.transformer.Log4j2PluginCacheFileTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</plugin>
This configuration takes care of:
Log4j2Plugins.dat
files. Without Log4j2PluginCacheFileTransformer
you can not use additional component libraries except log4j-api
and log4j-core
,ServiceResourceTransformer
you'll lose additional component like property sources,Edit: All these problems with the maven-shade-plugin
sum up to one: every time two jars have a file with the same name, it must be somehow merged.
That is why I prefer the spring-boot-maven-plugin
: instead of breaking multiple jars and adding their files into a single archive, it adds the original jars to the archive. The exact structure of the resulting jar is described in executable Jar format.
The usage is straightforward: just add the repackage
goal to your build and remove maven-shade-plugin
.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.10</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
This will effectively add the small spring-boot-loader
to your application. Version 2.x of the library requires Java 8, while version 3.x requires Java 17.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With