tl;dr: I'd like to filter out some unneeded logs (and leave other) from pdfbox
library. This library uses commons-logging
facade.
Longer version
I'd like to filter out some unneeded logs (and leave other) from pdfbox
library. It has in its own dependencies commons-logging
, which is (as I understand it) a facade similar to slf4j
. I also have another dependency (picocli
), which also has dependency to commons-logging
albeit with a newer version. There is a project called jcl-over-slf4j
which redirects logs coming from commons-logging
to slf4j
facade. I decided to use it together with logback-classic
, a logger that natively implements slf4j
. I also wrote a custom filter to filter out logs I don't need. Everything works fine when I run junit test (from IntelliJ and using CLI - by running mvn clean package
). But running the final (fat
) jar including my own code and all the dependencies results in a message printed out to console saying that I don't have any supported logger on classpath:
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
Why is that? It seems that everything works fine during test execution and fails to work when using fat jar.
UPDATE
As this really seems important, I will describe the fat
jar issue and how I run my application.
To create fat
jar I use the maven shade plugin
together with the configuration seen below. I create fat
jar by executing mvn clean package
and run the application by java -jar myapp.jar
.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.github.menteith.pdfexample.Main</mainClass>
<manifestEntries>
<Built-By />
</manifestEntries>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/**</exclude>
<exclude>module-info.class</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
Here's my custom Logback filter:
class LogbackTurboFilter
extends TurboFilter {
@Override
public FilterReply decide(final Marker marker, final Logger logger, final Level level,
final String format, final Object[] params, final Throwable t) {
System.out.println("In decide!!!"); // this is printed during tests, but not when final jar is run
if ( !isStarted() ) {
return FilterReply.NEUTRAL;
}
if ( level == Level.WARN
&& logger.getName().startsWith("org.apache.pdfbox") ) {
return FilterReply.DENY;
} else {
return FilterReply.NEUTRAL;
}
}
}
Here's my logback.xml
:
<configuration>
<turboFilter class="com.github.menteith.pdfexample.LogbackTurboFilter"/>
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%-4relative [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
Relevant parts of pom.xml
:
<dependency>
<artifactId>pdfbox</artifactId>
<groupId>org.apache.pdfbox</groupId>
<version>2.0.27</version>
<!-- picocli has never artifact -->
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.7.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.5</version>
</dependency>
And dependency tree
from maven
:
+- org.apache.pdfbox:pdfbox:jar:2.0.27:compile
| \- org.apache.pdfbox:fontbox:jar:2.0.27:compile
+- info.picocli:picocli:jar:4.7.1:compile
+- org.slf4j:jcl-over-slf4j:jar:2.0.6:compile
| \- org.slf4j:slf4j-api:jar:2.0.6:compile
+- ch.qos.logback:logback-classic:jar:1.4.5:compile
| \- ch.qos.logback:logback-core:jar:1.4.5:compile
+- org.bouncycastle:bcprov-jdk15on:jar:1.70:compile
+- org.bouncycastle:bcmail-jdk15on:jar:1.70:compile
| +- org.bouncycastle:bcutil-jdk15on:jar:1.70:compile
| \- org.bouncycastle:bcpkix-jdk15on:jar:1.70:compile
+- com.github.jai-imageio:jai-imageio-jpeg2000:jar:1.4.0:compile
| \- com.github.jai-imageio:jai-imageio-core:jar:1.4.0:compile
+- org.projectlombok:lombok:jar:1.18.24:provided
+- org.junit.jupiter:junit-jupiter-engine:jar:5.9.2:test
| +- org.junit.platform:junit-platform-engine:jar:1.9.2:test
| | +- org.opentest4j:opentest4j:jar:1.2.0:test
| | \- org.junit.platform:junit-platform-commons:jar:1.9.2:test
| +- org.junit.jupiter:junit-jupiter-api:jar:5.9.2:test
| \- org.apiguardian:apiguardian-api:jar:1.1.2:test
\- org.assertj:assertj-core:jar:3.24.0:test
\- net.bytebuddy:byte-buddy:jar:1.12.20:test