Best Practices
- Libraries shouldn't depend to a logging implementation (like log4j, logback or emaze-logging)
- Libraries shouldn't depend to
commons-logging
since it is deprecated and introduces a lot of complexity in the classloader - Libraries shouldn't use
java util logging
sinse it has serious performance problems - Libraries should use simply the SLF4J API
- Only the applications are logging-aware and configure the proper backend
Otherwise
- You limit your applications to the logging backend decided by the libraries
- Conflicts are inevitable
Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path, preempting StackOverflowError. See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.
Excluding jars from target
You can exclude dependencies at the top level configuring the maven-war-plugin
properly (see Including and Excluding Files From the WAR).
In this example it excludes the slf4j-log4j12
binding imported transitively by some dependency (since the application would use logback), but it keeps the log4j-over-slf4j
ensuring that all logging performed used log4j directly is forwarded to SLF4J.
<plugin>
<artifactId>maven-war-plugin</artifactId>
...
<configuration>
<packagingExcludes>
WEB-INF/lib/slf4j-log4j12-*.jar,
%regex[WEB-INF/lib/log4j-(?!over-slf4j).*.jar]
</packagingExcludes>
</configuration>
...
</plugin>
Using Spring Boot the wrong dependencies should be excluded from the bundle too:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
...
<configuration>
<excludes>
<exclude>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclude>
<exclude>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclude>
</excludes>
</configuration>
...
</plugin>