Lahiru Chandima Lahiru Chandima - 12 days ago 5
Java Question

How can I remove logback from a library's dependency while keeping SLF4J?

In my Vaadin project, I have a dependency on a certain library. This library uses slf4j for logging. In the library pom, logback slf4j binding is added as a runtime dependency.

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>


In my application, I directly use log4j for logging. I want the logs added by the library to go in my log4j log.

For this, I added following to my pom to include slf4j log4j binding

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>


However, slf4j complains that it has found multiple bindings.

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/program_files/apache-tomcat-8.0.24/temp/0-ROOT/WEB-INF/lib/logback-classic-1.0.13.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/program_files/apache-tomcat-8.0.24/temp/0-ROOT/WEB-INF/lib/slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]


I checked the dependency tree of my application, which has following for its dependency on logback. (Following is the only dependency on logback)

[INFO] | +- com.mycompany.mylib:libname:jar:1.1.0-SNAPSHOT:compile
[INFO] | | +- org.slf4j:jcl-over-slf4j:jar:1.7.5:runtime
[INFO] | | +- ch.qos.logback:logback-classic:jar:1.0.13:runtime
[INFO] | | | \- ch.qos.logback:logback-core:jar:1.0.13:runtime
[INFO] | | +- ch.qos.logback:logback-access:jar:1.0.13:runtime


Also, when I checked inside
WEB-INF\lib
directory in my war file, I found following jars.

logback-access-1.0.13.jar
logback-classic-1.0.13.jar
logback-core-1.0.13.jar


Why did logback ended up in my lib directory? As I have heard, runtime dependencies should not come into libs directory.

How should I resolve this? The library is developed within my company and I can ask the library developers to remove the logback runtime dependencies if needed.

Answer

Option 1: They change their pom.

The easiest way to fix this would be to have the library developers in your own company mark logback as optional and require SLF4J as a compile dependency explicitly. This is the right, canonical way to do SLF4J in Maven. In other words:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>${slf4j.version}</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>${logback.version}</version>
    <scope>runtime</scope>
    <optional>true</optional>
</dependency>

Option 2: You revise their dependencies in your pom.

If you want to fix it yourself, without going through them, then you can use the exclusions tag when declaring their dependency. In other words, in your pom, do:

<dependency>
    <groupId>your.company</groupId>
    <artifactId>libraryname</artifactId>
    <version>${theirlibrary.version}</version>
    <exclusions>
        <exclusion>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </exclusion>
    </exclusions>
</dependency>

You asked if there's an reason to depend on Logback directly; generally there isn't, for a library author. Their pom configuration is probably just a minor oversight on their part. There are some reasons to depend on logback specifically, but they have to do with startup (stuff with JoranConfigurator or StatusPrinter, that sort of thing, which shouldn't come up with a library. Other reasons to call Logback classes directly include stuff like custom appenders, which, again, shouldn't come up in a library, only a deployed app.

Comments