5

I am in the process of refactoring a Java web application which has a fairly large number of dependencies. I would like to use slf4j, with log4j2 as the underlying logging implementation. However, the application includes some Spring dependencies. Spring using JCL (Jakarta common logging) for its logging, so it is bringing in commons-logging as a transitive dependency. This is a potential problem, because it means that slf4j might pick up on jcl as a logging implementation, and that Spring might log somewhere in an undesirable way.

From the slf4j documentation, the solution is to first turn off commons-logging by excluding it from the POM, then to use jcl-over-slf4j to replace commons-logging. Of course, jcl-over-slf4j will route all previous logging calls made by Spring to slf4j.

I have tried excluding commons-logging, e.g.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <exclusions>
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

However, when checking the Maven dependency tree, commons-logging still showed up now as a dependency of json-lib, another dependency which the project has.

It became clear quickly that manually excluding all unwanted logging dependencies would not scale well. The slf4j documentation goes on to suggest using scope provided as an option:

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <scope>provided</scope>
</dependency>

However, as this SO question discusses, this approach still means that the other logging frameworks would be present during testing. Also, it is not clear to me whether this provided option would apply to all versions of commons-logging, or would a specific entry be needed for each version. If the latter be the case, then this would be as tedious as just manually excluding commons-logging everywhere.

What is the best practice for excluding unwanted logging dependencies to configure slf4j in a Java application?

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • "It became clear quickly that manually excluding all unwanted logging dependencies would not scale well." - Is this really a problem? Can't you use the dependency tree to find where to add the exclusion and use some script to add these? – SpaceTrucker Jun 17 '19 at 14:47
  • @SpaceTrucker It is a whack-a-mole problem...the dependency tree changes after excluding each occurrence, so the script you have in mind might be fairly non trivial. – Tim Biegeleisen Jun 17 '19 at 14:49
  • Related to your question, but more food for thought than something to address your dependency questions: https://stackoverflow.com/a/41500347/3284624 – D.B. Jun 17 '19 at 23:34
  • In regard to your dependency questions, the maven user guide suggests the [banned dependencies rule](https://maven.apache.org/enforcer/enforcer-rules/bannedDependencies.html) and "When the build fails, you'll need to add specific exclusions on each path the enforcer finds." I'm hoping that means it will tell you everything that includes the unwanted dependency so you can add all the exclusions at once. – D.B. Jun 17 '19 at 23:49

1 Answers1

1

Commons logging is not an slf4j implementation. Just leave it on the class path and include Log4J-Jcl to route all commons logging calls to Log4J.

rgoers
  • 8,696
  • 1
  • 22
  • 24
  • This doesn't completely address my issue though, because JCL, if left alone, might continue logging on its own. I am looking for a general solution to pipe _all_ existing logging functionality through slf4j. – Tim Biegeleisen Jun 18 '19 at 06:29
  • 1
    Why? Your goal should be to have all logging go to the desired logging implementation. With Log4J you do that by using Log4J-jcl. You could replace the commons logging jar with slf4j’s commons logging jar, but that will just add an extra layer by having the commons logging calls go through slf4j to Log4J, so why do that? – rgoers Jun 18 '19 at 06:34