Spring Boot: use logback instead of log4j

14,314

Solution 1

you already know this, but i wanted to wrap it up and generalize...


there are these three logging frameworks:

  • log4j (ancient)
  • slf4j (api used everywhere, there are different backends available)
  • logback (has nice features and configuration, successor of slf4j)

you have to manually throw out log4j and replace it with the compatibility bridge log4j-over-slf4j.

there is a slf4j backend called logback-classic.


mvn:

<dependency>
    <!-- legacy log4j ==> slf4j -->
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.21</version>
</dependency>
<dependency>
    <!-- slf4j ==> logback -->
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.1.7</version>
</dependency>
<dependency>
    <groupId>...no maintainer...</groupId>
    <artifactId>...old stuff...</artifactId>
    <version>...ancient...</version>
    <exclusions>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>

sbt:

libraryDependencies ++= Seq(
    Seq(...),
    Seq(
      "org.slf4j" % "log4j-over-slf4j" % "1.7.21",   // legacy log4j --> slf4j
      "ch.qos.logback" % "logback-classic" % "1.1.7" // slf4j --> logback
    )
  ).flatten.map(_.excludeAll(
    ExclusionRule(organization = "log4j", name = "log4j", artifact = "*"),
    ExclusionRule(organization = "org.slf4j", name = "slf4j-log4j12", artifact = "*")
  ))

Solution 2

Spring Boot by default using Logback for its logging. There is no need for adding it explicitly:

By default, If you use the ‘Starter POMs’, Logback will be used for logging. Appropriate Logback routing is also included to ensure that dependent libraries that use Java Util Logging, Commons Logging, Log4J or SLF4J will all work correctly.

You can also, change the log levels through using logging.level.*=LEVEL in your application.properies.

Share:
14,314

Related videos on Youtube

Alex Woolford
Author by

Alex Woolford

I was born in the United Kingdom and moved to the United States in 2004 following a go-for-broke journey across India, south-east Asia, and Australia. I now live in Lafayette, CO with my wife and two boys. I'm particularly interested in data science using Python, R and (most recently) Java.

Updated on September 21, 2022

Comments

  • Alex Woolford
    Alex Woolford over 1 year

    I'd like to use Logback, for its performance and flexibility, with a Spring Boot project. I added the Logback dependencies to pom.xml:

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.1.3</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.1.3</version>
    </dependency>
    

    ... and ensured that the logging, within each of the classes in my project, was created like this:

    public class MyClass {
    
        static final Logger LOG = LoggerFactory.getLogger(MyClass.class);
    

    When the project starts, the following warning is displayed in the console:

    log4j:WARN No appenders could be found for logger (org.springframework.boot.logging.ClasspathLoggingApplicationListener).
    log4j:WARN Please initialize the log4j system properly.
    log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
    

    It seems that Spring is still trying to use log4j and not logback. I tried adding logging.config=classpath:logback.xml to the Spring application.properties, but it didn't resolve the issue.

    Can you see what I'm doing wrong?

    Update

    Both @AliDehghani and @chrylis suggested that log4j is being referenced by another package in the pom. The output from mvn dependency:tree confirmed that hbase-common was the source:

    com.woolford:my-project:jar:1.0-SNAPSHOT
    +- org.apache.hbase:hbase-common:jar:1.1.2:compile
    |  [... etc ...]
    |  +- commons-logging:commons-logging:jar:1.2:compile
    |  [... etc ...]
    |  +- org.apache.hadoop:hadoop-common:jar:2.5.1:compile
    |  [... etc ...]
    |  |  +- org.slf4j:slf4j-log4j12:jar:1.7.5:compile
    |  |  \- com.jcraft:jsch:jar:0.1.42:compile
    |  +- org.apache.hadoop:hadoop-mapreduce-client-core:jar:2.5.1:compile
    |  [... etc ...]
    |  +- log4j:log4j:jar:1.2.17:compile
    |  [... etc ...]
    \- org.apache.hbase:hbase-client:jar:1.1.2:compile
       [... etc ...]
    

    I tried excluding log4j (and slf4j) from hbase-common like this:

    <dependency>
        <groupId>org.apache.hbase</groupId>
        <artifactId>hbase-common</artifactId>
        <version>1.1.2</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
            </exclusion>
            <exclusion>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    

    The project failed to build:

    [ERROR] Failed to execute goal on project my-project: Could not resolve dependencies for project com.woolford:my-project:jar:1.0-SNAPSHOT: The following artifacts could not be resolved: javax.jms:jms:jar:1.1, com.sun.jdmk:jmxtools:jar:1.2.1, com.sun.jmx:jmxri:jar:1.2.1: Could not transfer artifact javax.jms:jms:jar:1.1 from/to java.net (https://maven-repository.dev.java.net/nonav/repository): Cannot access https://maven-repository.dev.java.net/nonav/repository with type legacy using the available connector factories: BasicRepositoryConnectorFactory: Cannot access https://maven-repository.dev.java.net/nonav/repository with type legacy using the available layout factories: Maven2RepositoryLayoutFactory: Unsupported repository layout legacy -> [Help 1]
    

    I tried adding these dependencies to pom.xml, but that didn't help.

    @AliDehghani noted, in his answer below, that Spring Boot uses Logback by default and so adding logback-core and logback-classic to the pom.xml shouldn't be necessary. I'm sure he's 100% correct. However, when I comment out the logback-core and logback-classic in pom.xml I see several warnings, e.g.

    log4j:ERROR Could not create an Appender. Reported error follows.
    java.lang.ClassNotFoundException: ch.qos.logback.core.ConsoleAppender
    
    • chrylis -cautiouslyoptimistic-
      chrylis -cautiouslyoptimistic- about 8 years
      Is some other dependency also pulling in log4j? You might need to exclude it.
  • Ali Dehghani
    Ali Dehghani about 8 years
    Add your complete pom.xml to question. Maybe some other dependency also pulling in log4j.
  • Ali Dehghani
    Ali Dehghani about 8 years
    org.apache.hbase:hbase-common -> log4j:log4j
  • Ali Dehghani
    Ali Dehghani about 8 years
    Apparently, HBase depends on log4j. Exclude log4j dependency from Hbase dependency declaration.
  • Ali Dehghani
    Ali Dehghani about 8 years