Home > Java > Configuring Maven to use SLF4J

Configuring Maven to use SLF4J

I mainly write articles for two reasons: to understand something that is new to me or to document something I regularly have to explain to others. This article definitely falls in the second category: in order to celebrate the new 1.0.0 version of Logback, I’ve decided to write down once and for all how to properly use SLF4J with Maven since it seems there’s no shortage of questions about it.

Basics

The basis of SLF4J is to have two separate components, one API and one implementation. That means that your code should solely be dependent on the API thus the implementation can be changed at your convenience. Remember that decoupling code from implementations by introducing an interface should be your first concern: at the library level, it’s the role of an API.

This is easily done like this in your POM:


	
		
			org.slf4j
			slf4j-api
			1.6.4
		
		
			ch.qos.logback
			logback-classic
			runtime
			1.0.0
		
	

The runtime scope prevents us from using Logback’s implementation classes when coding, which achieves decoupling.

Note: if you’re using a parent POM for your project (because you have modules), it goes without saying the above dependencies should be under the dependencyManagement section.

Bridging

Since an application with only logging features is a bit limited, it’s highly likely we’ll need other dependencies. Of course, some of those dependencies may use other logging frameworks, such as Commons Logging or Log4J.

For example, Spring uses Commons Logging: thus, logs produced by our application would use logback while those produced by Spring would use Commons Logging. This strategy needs two different configurations files (as well as knowledge of both) which is not very intuitive. Moreover, this would be unwieldly when reading twothe flow on two different sources. Note that this could be mitigated by using logging targets other than files (which I haven’t seen yet).

Fortunately, SLF4J provides bridging components that let us wire third-party API calls directly to SLF4J. For Spring, that means removing all dependencies to Commons Logging and replacing them with a single dependency to the Commons Logging to SLF4 bridge.


	
		
			org.springframework
			spring-core
			3.0.0
			
				
					commons-logging
					commons-logging
				
			
		
		
			org.springframework
			spring-beans
			3.0.0
			
				
					commons-logging
					commons-logging
				
			
		
		
			org.springframework
			spring-context
			3.0.0
			
				
					commons-logging
					commons-logging
				
			
		
		
			org.slf4j
			jcl-over-slf4j
			1.6.2
		
	

Like in the section above, you should preferably use the

Note: although this knowledge is by no means necessary, know that since API and implementation are both packages together in the commons-logging.jar, the jcl-over-slf4.jar bridge completely replaces the API classes provided by Commons Logging. That means you shouldn’t have both JAR in your classpath!

Troubleshooting

Remember the Highlander rule: “there can be only one”. In this case, there can be only one implementation available on the classpath since SLF4J uses the Java Services Provider. If its the case, SLF4J will display a “Multiple bindings were found on the class path” warning and uses the first it finds (first on the classpath). Since classpaths are ordered by Maven, there’s little chance it will be the thing we want. Thus, take care of not putting slf4j-simple in the test scope along with logback or be prepared to face undetermined side-effects.

To go further:

email
Send to Kindle
Categories: Java Tags: ,
  1. November 7th, 2011 at 01:53 | #1

    I would rather exclude commons-logging everywhere by declaring it with scope provided, as suggested in the SLF4J FAQ: http://www.slf4j.org/faq.html#excludingJCL

  2. November 7th, 2011 at 10:29 | #2

    Hi,

    Nice guide, would recommend to also use the enforcer-plugin to break the build if any commons-logging or log4j gets included in the dependencies.

    <plugin>
    	<groupId>org.apache.maven.plugins</groupId>
    	<artifactId>maven-enforcer-plugin</artifactId>
    	<version>1.0.1</version>
    	<executions>
    	  <execution>
    		<id>enforce-versions</id>
    		<goals>
    		  <goal>enforce</goal>
    		</goals>
    		<configuration>
    		  <rules>
    			<bannedDependencies>
    			  <excludes>
    				<exclude>commons-logging:commons-logging</exclude>
    				<exclude>log4j:log4j</exclude>
    			  </excludes>
    			</bannedDependencies>
    		  </rules>
    		</configuration>
    	  </execution>
    	</executions>
     </plugin>

    I also delegate log4j-over-slf4j, so included below.

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>log4j-over-slf4j</artifactId>
        <version>1.6.4</version>
    </dependency>

    Also included

    <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>jul-to-slf4j</artifactId>
         <version>1.6.4</version>
    </dependency>

    and added configuration to logback.xml

    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
        <resetJUL>true</resetJUL>
    </contextListener>

    All the best, Pether

  3. November 7th, 2011 at 22:07 | #3

    I’ve noticed an error in the article. The depency on logback-core should be changed to logback-classic. Please correct. Once a dependency is declared on logback-classic, declaring a dependency on logback-core is superfluous, as logback-classic will pull in logback-core by maven’s transitivity rules. Thank you for a helpful article.

  4. November 7th, 2011 at 22:54 | #4

    Thanks for your feedback: dependency corrected.

  5. November 8th, 2011 at 11:22 | #5

    You can use the Maven Tattletale plugin to check that there are not duplicated log implementations, by finding any duplicated classes

    http://blog.carlossanchez.eu/2011/03/23/finding-duplicate-classes-in-your-war-files-with-tattletale/

  6. November 8th, 2011 at 12:11 | #6

    I see from this article that it is possible to replace Clogging with SLF4J for Spring, but I’m confused as to what functionality this adds to Spring (a Dependency Injection Framework/Container). In word word: why ?

  1. No trackbacks yet.