23

From what I have seen in example spring pom.xml files is that they add a few entries for slf4j and log4j and somehow when you use log4j in your spring application it will be wrapped by slf4j library.

Can someone explain to me how this magically happens?

Vadzim
  • 24,954
  • 11
  • 143
  • 151
codecompleting
  • 9,251
  • 13
  • 61
  • 102

3 Answers3

29

Spring still uses commons-logging for all the internal logging (backwards compatibility). If you wish to use some other logging framework (log4j) then you need to bridge the calls from commons logging to your framework of choice. Otherwise you will have to maintain multiple logging configurations.

slf4j acts as a simple facade for various logging frameworks (jul, log4j, jcl, logback) and allows you to plug in the desired logging framework at deployment time.

Instead of using the logging framework implementation that is imposed by the third party framework you provide the slf4j's bridge implementation that acts like the real thing but really just forwards the logging calls to slf4j or its concrete binding.

Logging section of Maven pom.xml usually looks like this:

<!-- remove the real commons-logging from classpath -->
<!-- declare as provided or exclude from spring jars -->
<dependency>
    <artifactId>commons-logging</artifactId>
    <groupId>commons-logging</groupId>
    <version>1.0</version>
    <scope>provided</scope>
</dependency>

<!-- add slf4j interfaces to classpath -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.6.4</version>
    <scope>compile</scope>
</dependency>

<!-- add commons logging to slf4j bridge to classpath --> 
<!-- acts as jcl but routes commons-logging calls to slf4j -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.6.4</version>
    <scope>runtime</scope>
</dependency>

<!-- add log4j binding to classpath -->
<!-- routes slf4j calls to log4j -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.4</version>
    <scope>runtime</scope>
</dependency>

<!-- add log4j to classpath -->
<!-- does the logging -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.16</version>
</dependency>

This has nothing to do with the Spring container nor dependency injection, it is pure classpath, classloader stuff...

Please see the following links for further details.

Bruno Dević
  • 291
  • 2
  • 3
  • While this answer is pretty good, there is one inaccuracy in it: SLF4J isn't *bridged* over commons logging, the `jcl-over-slf4j` dependency *contains a reimplementation of the commons logging API*. This is why it is critical to make sure that commons logging isn't on your classpath, because the two modules use the same package name (as a necessity) and therefore conflict with each catastrophically. Spring's "context" module contains a dependency on "spring-core" which contains a dependency on "commons-logging", which is why you have to take active measures to prevent this when using Spring – Periata Breatta Oct 30 '16 at 12:08
  • It's also a bit cleaner to specifically exclude the dependency on commons-logging in Spring, which you can do as described in [this article on Spring's web site](https://spring.io/blog/2009/12/04/logging-dependencies-in-spring), rather than telling Maven you already have it on your classpath (which is a bit of a hack, really). – Periata Breatta Oct 30 '16 at 12:11
5

slf4j is a logging API, which doesn't do anything, just bunch of interfaces. log4j is a logging system, with concrete classes. there is a slf4j-log4j library which uses log4j as a backend for the slf4j API.

Some projects explicitly depend on log4j, they call concrete classes. So, you cannot use another backend (e.g. logback or j.u.l or apache commons or whatever) for your project which you wisely made using the slf4j API only.

There is a trick to substitute log4j classes by a mock implementation (the bridge) which just simply redirects all calls to the sl4j. In maven you just declare a dependency with very high version number and this mock considered as ultra-modern log4j library.

kan
  • 28,279
  • 7
  • 71
  • 101
-1

try with adding :

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
Yavor
  • 1
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 18 '22 at 16:06