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
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 = "*")
))
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.
Related
I'm getting the following error:
Exception in thread "main" java.lang.NoClassDefFoundError:
org/slf4j/LoggerFactory
I need to include slf4j as a dependency but I'm not sure which jar file to download from https://repo1.maven.org/maven2/org/slf4j/.
I tried org/slf4j/slf4j-api which doesn't work. How do I determine which one is correct?
slf4j is a library that is used as an abstraction of each logging implementation framework such as log4j, logback or Jakarta Commons Logging. If your intent is to use it, you have to also define the concrete framework you want to use under the wood, for example for log4j, your pom dependencies will look like this:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
Depending on the framework you want to use, the dependencies will be a bit different.
This excellent link will give your more details.
SLF4J is a logging API. Combine it with Logback (written by the same people as SLF4J) which implements that logging API:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
</dependency>
Find the latest stable versions on mvnrepository.com. Currently logback 1.2.11 and slf4J 1.7.32. Note the the vulnerabilities mentioned on logback 1.2.11 are because of an optional dependency on log4J 1.x (which you don't get automatically, so it's safe to use logback 1.2.11 at the time of writing).
I've started writing a new application in Java 11 and while running the application I got this below error. I read about this issue and looks like it is a case of split package . But I'm not sure how can I fix this issue.
java.lang.module.ResolutionException: Modules slf4j.log4j12 and log4j export package org.apache.log4j to module kubernetes.model.common
I've below dependencies in pom for log4j and slf4j.
log4j
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.26</version>
</dependency>
log4j2
When I tried to use log4j2 with following dependencies I got different error
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.6</version>
java.lang.module.ResolutionException: Modules log4j.core and log4j.api export package org.apache.logging.log4j to module java.annotation
slf4j-log4j12 contains a class named org.apache.log4j.MDCFriend.
As I recall this is to fix a bug in log4j 1.x that occurred when the version detection pattern was changed in Java 9. Since Log4j 1.x reached the end of life in August 2015 the bug cannot be fixed there so SLF4J introduced this "fix". Unfortunately, using the org.apache.log4j package outside of the log4j jar is forbidden in the Java module system which is what is causing the problem you are seeing.
Also, note that the security bug CVE-2019-17571 has been created for Log4j 1.x. While your application probably won't be vulnerable to the problem it will show up on security scans.
You have a few options:
Create a bug report against SLF4J and hope that it gets fixed.
Create your own fork of slf4j-log4j12 and fix it yourself.
Upgrade from Log4j 1 to Log4j 2 (the solution I would recommend for a new application).
Use an SLF4J implementation other than Log4j 2.
I encounterd the same error, but when I use log4j-core version 2.13.3 ,the error disappears.
We are using hadoop-hdfs 3.2.1 jar and it has a transitive dependency on log4j 1.2.17 . In our central NexusIQ scan, it's giving a level 9 issue for log4j dependency. Is there a way to override log4j to log4j2 or any other solution.
I tried dependency management but there is no jar in log4j2 with artifact id log4j to override the transitive dependency.
Short answer: no that's not possible. You don't have a way of overriding a transitive dependency at the Nexus level. You'll have to use a different version of hadoop-hdfs, or compile it yourself with a "safe" log4j version.
I did manage to solve the similar issue for hbase-shaded-client jar where I had to exclude log4j 1.2.17 dependency.
For that, I did this.
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>...</version>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
</exclusions>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
It worked.
Answer Source
In my Vaadin project, I have a dependency on a certain library. This library uses slf4j for logging. In the library pom, logback slf4j binding is added as a runtime dependency.
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
In my application, I directly use log4j for logging. I want the logs added by the library to go in my log4j log.
For this, I added following to my pom to include slf4j log4j binding
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
However, slf4j complains that it has found multiple bindings.
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/D:/program_files/apache-tomcat-8.0.24/temp/0-ROOT/WEB-INF/lib/logback-classic-1.0.13.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/D:/program_files/apache-tomcat-8.0.24/temp/0-ROOT/WEB-INF/lib/slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class]
I checked the dependency tree of my application, which has following for its dependency on logback. (Following is the only dependency on logback)
[INFO] | +- com.mycompany.mylib:libname:jar:1.1.0-SNAPSHOT:compile
[INFO] | | +- org.slf4j:jcl-over-slf4j:jar:1.7.5:runtime
[INFO] | | +- ch.qos.logback:logback-classic:jar:1.0.13:runtime
[INFO] | | | \- ch.qos.logback:logback-core:jar:1.0.13:runtime
[INFO] | | +- ch.qos.logback:logback-access:jar:1.0.13:runtime
Also, when I checked inside WEB-INF\lib directory in my war file, I found following jars.
logback-access-1.0.13.jar
logback-classic-1.0.13.jar
logback-core-1.0.13.jar
Why did logback ended up in my lib directory? As I have heard, runtime dependencies should not come into libs directory.
How should I resolve this? The library is developed within my company and I can ask the library developers to remove the logback runtime dependencies if needed.
Option 1: They change their pom.
The easiest way to fix this would be to have the library developers in your own company mark logback as optional and require SLF4J as a compile dependency explicitly. This is the right, canonical way to do SLF4J in Maven. In other words:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
Option 2: You revise their dependencies in your pom.
If you want to fix it yourself, without going through them, then you can use the exclusions tag when declaring their dependency. In other words, in your pom, do:
<dependency>
<groupId>your.company</groupId>
<artifactId>libraryname</artifactId>
<version>${theirlibrary.version}</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
You asked if there's an reason to depend on Logback directly; generally there isn't, for a library author. Their pom configuration is probably just a minor oversight on their part. There are some reasons to depend on logback specifically, but they have to do with startup (stuff with JoranConfigurator or StatusPrinter, that sort of thing, which shouldn't come up with a library. Other reasons to call Logback classes directly include stuff like custom appenders, which, again, shouldn't come up in a library, only a deployed app.
I am using logback for my logging and it has been working however; the other day I started getting a warning
log4j:WARN No appenders could be found for logger (org.apache.axis.i18n.ProjectResourceBundle).
log4j:WARN Please initialize the log4j system properly.
I am not using log4j nor have I ever with this project.
I have a logback.xml in my resources folder.
Any ideas on why this warning started to show up?
You must be using a library that does use log4j. Can you post anything more about your project?
You should probably just put log4j bridge on the classpath. Read more here:
http://www.slf4j.org/legacy.html
The jar you want to look into is log4j-over-slf4j. It will bridge log4j API to actually make calls to your implementation of slf4j API (in your case - logback).
If you are using Maven to build your project then it might be as simple as putting
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.7</version>
</dependency>
in dependencies.
Excluding a library (if needed) would be done in this fashion (this assumes we are talking about the transitive dependency from the jar you've mentioned):
<dependency>
<groupId>org.swift.common</groupId>
<artifactId>jira-soap</artifactId>
<version>4.4.0</version>
<exclusions>
<exclusion>
<groupId>...</groupId>
<artifactId>...</artifactId>
</exclusion>
</exclusions>
</dependency>
Took me some time to find out since the message was log4j:WARN No appenders could be found for logger
I tried to exclude log4j and I tried the log4j-over-slf4j.
Then I ran mvn dependency:tree and finally found out that mye commons-configuration actually was using commons-logging
[INFO] +- commons-configuration:commons-configuration:jar:1.9:compile
[INFO] | \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] +- ch.qos.logback:logback-classic:jar:1.0.13:compile
[INFO] | +- ch.qos.logback:logback-core:jar:1.0.13:compile
[INFO] | \- org.slf4j:slf4j-api:jar:1.7.5:compile
[INFO] +- org.slf4j:log4j-over-slf4j:jar:1.7.6:compile
[INFO] \- org.apache.commons:commons-lang3:jar:3.1:compile
This became the solution for me.
<!-- logging with logback (and slf4j)-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.13</version>
</dependency>
<!-- had a dep in commons-configuration -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.6</version>
</dependency>