Sunday, December 21, 2014

Configuring Log4J with Slf4J in Spring-based application

While working with a Spring Boot based application, the spring-boot jar brings in the sl4j related jars which seems to be configured to jakarta-commons-logging by default. So, the log4j.properties in the classpath was never read by the log4j system.

To make log4j work with sl4j in this scenario, the sl4j dependencies coming from spring-boot have been excluded as follows:


<dependency>
 <groupid>org.springframework.boot</groupid>
 <artifactid>spring-boot-starter-data-rest</artifactid>
 <version>${spring-boot-version}</version>
 <exclusions>
  <exclusion>
   <groupid>org.slf4j</groupid>
   <artifactid>slf4j-api</artifactid>
  </exclusion>
  <exclusion>
   <groupid>org.slf4j</groupid>
   <artifactid>jul-to-slf4j</artifactid>
  </exclusion>
  <exclusion>
   <groupid>org.slf4j</groupid>
   <artifactid>log4j-over-slf4j</artifactid>
  </exclusion>
  <exclusion>
   <groupid>org.slf4j</groupid>
   <artifactid>jcl-over-slf4j</artifactid>
  </exclusion>
  <exclusion>
   <groupid>ch.qos.logback</groupid>
   <artifactid>logback-classic</artifactid>
  </exclusion>
 </exclusions>
</dependency>

Then, the sl4j and log4j dependencies are pulled in separately, as follows:

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
            <scope>runtime</scope>
        </dependency>

The Spring Test library seems to require JCL (jakarta-commons-logging) as it was throwing the following exception:


java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
 at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.clinit(SpringJUnit4ClassRunner.java:86)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
 at java.lang.reflect.Constructor.newInstance(Unknown Source)


Included the jcl-over-slf4j dependency to fix the above exception:
 
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>${slf4j.version}</version>
</dependency>


Now, the log4j.properties file in src/main/resources is read by the log4j system, without any additional configuration.