Slf4j: Difference between revisions
(29 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
=External= | |||
* Latest Version: https://www.slf4j.org/download.html | |||
=Internal= | =Internal= | ||
* [[Java#Libraries|Java]] | * [[Java#Libraries|Java]] | ||
* [[log4j]] | |||
=Playground Code= | |||
<blockquote style="background-color: AliceBlue; border: solid thin LightSteelBlue;"> | |||
:https://github.com/NovaOrdis/playground/tree/master/slf4j<br> | |||
</blockquote> | |||
=Dependency= | |||
<syntaxhighlight lang='groovy'> | |||
dependencies { | |||
compileOnly('org.slf4j:slf4j-api:1.7.6') | |||
} | |||
</syntaxhighlight> | |||
=Bindings= | |||
SLF4J needs an actual binding to a known logging framework. The binding is executed at runtime by the class <tt>org.slf4j.impl.StaticLoggerBinder</tt>, which is embedded in biding libraries. If no SLF4J binding library could be found on the class path, you will see 'Failed to load class "org.slf4j.impl.StaticLoggerBinder"' ([[#No_StaticLoggerBinder|see below for more details]]). | |||
If you are building an embedded component such as a library or a framework, it must not declare a dependency on any SLF4J binding, but only on slf4j-api. When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J's purpose. | |||
If you are building a runtime that actually does logging, one (and only one) of slf4j-nop.jar, slf4j-simple.jar, [[#log4j12_Binding|slf4j-log4j12.jar]], slf4j-jdk14.jar or logback-classic.jar must be added to the classpath. If you add more than one binding to the classpath, you will see "Class path contains multiple SLF4J bindings" ([[#Multiple_SLF4J_Bindings|see below for more details]]). Note that slf4j-nop.jar provide just null logging. | |||
==log4j12 Binding== | |||
If you want an application that uses slf4j-api to actually log with log4j, add the "slf4j-log4j12.jar" binding to the classpath. | |||
<syntaxhighlight lang='groovy'> | |||
dependencies { | |||
implementation('org.slf4j:slf4j-log4j12:1.7.6') | |||
} | |||
</syntaxhighlight> | |||
If the slf4j-log4j12 dependency is introduced with Maven, slf4j-log4j12 will transitively declare a dependency on log4j: | |||
[[Image:slf4j-log4j12_Dependencies.png]] | |||
If the classpath is assembled by hand, log4j must be added to the classpath, otherwise we'll get: | |||
<syntaxhighlight lang='text'> | |||
Failed to instantiate SLF4J LoggerFactory | |||
Reported exception: | |||
java.lang.NoClassDefFoundError: org/apache/log4j/Level | |||
[...] | |||
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Level | |||
[...] | |||
</syntaxhighlight> | |||
==Logback Binding== | |||
<syntaxhighlight lang='groovy'> | |||
dependencies { | |||
testImplementation('ch.qos.logback:logback-classic:1.2.3') | |||
} | |||
</syntaxhighlight> | |||
=API= | |||
=Exception Logging= | |||
<syntaxhighlight lang='java'> | |||
log.error("failure", e); | |||
</syntaxhighlight> | |||
Result: | |||
<syntaxhighlight lang='text'> | |||
2018-11-09 13:17:52.947 ERROR 9064 --- [ main] p.s.l.SpringbootLoggingApplication : failure | |||
java.lang.IllegalStateException: we are in an illegal state | |||
at playground.springboot.logging.subpack.SomeClass.run(SomeClass.java:12) ~[classes!/:na] | |||
at playground.springboot.logging.SpringbootLoggingApplication.run(SpringbootLoggingApplication.java:25) [classes!/:na] | |||
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813) [spring-boot-2.1.0.RELEASE.jar!/:2.1.0.RELEASE] | |||
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:797) [spring-boot-2.1.0.RELEASE.jar!/:2.1.0.RELEASE] | |||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) [spring-boot-2.1.0.RELEASE.jar!/:2.1.0.RELEASE] | |||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.0.RELEASE.jar!/:2.1.0.RELEASE] | |||
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.0.RELEASE.jar!/:2.1.0.RELEASE] | |||
at playground.springboot.logging.SpringbootLoggingApplication.main(SpringbootLoggingApplication.java:15) [classes!/:na] | |||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181] | |||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181] | |||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181] | |||
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181] | |||
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [springboot-logging-0.0.1-SNAPSHOT.jar:na] | |||
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [springboot-logging-0.0.1-SNAPSHOT.jar:na] | |||
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [springboot-logging-0.0.1-SNAPSHOT.jar:na] | |||
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) [springboot-logging-0.0.1-SNAPSHOT.jar:na] | |||
</syntaxhighlight> | |||
==Format== | |||
<syntaxhighlight lang='java'> | |||
log.info("accessed by {} on {}", user, date); | |||
</syntaxhighlight> | |||
=Troubleshooting= | =Troubleshooting= | ||
==No StaticLoggerBinder== | |||
<pre> | |||
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". | |||
SLF4J: Defaulting to no-operation (NOP) logger implementation | |||
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. | |||
</pre> | |||
SLF4J needs an actual binding to a known logging framework. The above message means that the binding, provided by org.slf4j.impl.StaticLoggerBinder, was not found, which means that no appropriate SLF4J binding could be found on the class path. | |||
To fix, you need to place one (and only one) of slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar or logback-classic.jar on the classpath. | |||
If you are packaging an application and you do not care about logging, then placing slf4j-nop.jar on the class path of your application will get rid of this warning message. Note that embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on slf4j-api. When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J's purpose. | |||
==Multiple SLF4J Bindings== | ==Multiple SLF4J Bindings== |
Latest revision as of 01:38, 23 February 2019
External
- Latest Version: https://www.slf4j.org/download.html
Internal
Playground Code
Dependency
dependencies {
compileOnly('org.slf4j:slf4j-api:1.7.6')
}
Bindings
SLF4J needs an actual binding to a known logging framework. The binding is executed at runtime by the class org.slf4j.impl.StaticLoggerBinder, which is embedded in biding libraries. If no SLF4J binding library could be found on the class path, you will see 'Failed to load class "org.slf4j.impl.StaticLoggerBinder"' (see below for more details).
If you are building an embedded component such as a library or a framework, it must not declare a dependency on any SLF4J binding, but only on slf4j-api. When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J's purpose.
If you are building a runtime that actually does logging, one (and only one) of slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar or logback-classic.jar must be added to the classpath. If you add more than one binding to the classpath, you will see "Class path contains multiple SLF4J bindings" (see below for more details). Note that slf4j-nop.jar provide just null logging.
log4j12 Binding
If you want an application that uses slf4j-api to actually log with log4j, add the "slf4j-log4j12.jar" binding to the classpath.
dependencies {
implementation('org.slf4j:slf4j-log4j12:1.7.6')
}
If the slf4j-log4j12 dependency is introduced with Maven, slf4j-log4j12 will transitively declare a dependency on log4j:
If the classpath is assembled by hand, log4j must be added to the classpath, otherwise we'll get:
Failed to instantiate SLF4J LoggerFactory
Reported exception:
java.lang.NoClassDefFoundError: org/apache/log4j/Level
[...]
Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Level
[...]
Logback Binding
dependencies {
testImplementation('ch.qos.logback:logback-classic:1.2.3')
}
API
Exception Logging
log.error("failure", e);
Result:
2018-11-09 13:17:52.947 ERROR 9064 --- [ main] p.s.l.SpringbootLoggingApplication : failure
java.lang.IllegalStateException: we are in an illegal state
at playground.springboot.logging.subpack.SomeClass.run(SomeClass.java:12) ~[classes!/:na]
at playground.springboot.logging.SpringbootLoggingApplication.run(SpringbootLoggingApplication.java:25) [classes!/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813) [spring-boot-2.1.0.RELEASE.jar!/:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:797) [spring-boot-2.1.0.RELEASE.jar!/:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) [spring-boot-2.1.0.RELEASE.jar!/:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.0.RELEASE.jar!/:2.1.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.0.RELEASE.jar!/:2.1.0.RELEASE]
at playground.springboot.logging.SpringbootLoggingApplication.main(SpringbootLoggingApplication.java:15) [classes!/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [springboot-logging-0.0.1-SNAPSHOT.jar:na]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [springboot-logging-0.0.1-SNAPSHOT.jar:na]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [springboot-logging-0.0.1-SNAPSHOT.jar:na]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) [springboot-logging-0.0.1-SNAPSHOT.jar:na]
Format
log.info("accessed by {} on {}", user, date);
Troubleshooting
No StaticLoggerBinder
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
SLF4J needs an actual binding to a known logging framework. The above message means that the binding, provided by org.slf4j.impl.StaticLoggerBinder, was not found, which means that no appropriate SLF4J binding could be found on the class path.
To fix, you need to place one (and only one) of slf4j-nop.jar, slf4j-simple.jar, slf4j-log4j12.jar, slf4j-jdk14.jar or logback-classic.jar on the classpath.
If you are packaging an application and you do not care about logging, then placing slf4j-nop.jar on the class path of your application will get rid of this warning message. Note that embedded components such as libraries or frameworks should not declare a dependency on any SLF4J binding but only depend on slf4j-api. When a library declares a compile-time dependency on a SLF4J binding, it imposes that binding on the end-user, thus negating SLF4J's purpose.
Multiple SLF4J Bindings
If the classpath contains two or more JARs with SLF4J bindings, we get this:
SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/Users/ovidiu/runtime/os-stats-1.0.1-SNAPSHOT-6/lib/slf4j-log4j12-1.7.12.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/Users/ovidiu/runtime/jboss-eap-6.4.6/modules/system/layers/base/org/slf4j/impl/main/slf4j-jboss-logmanager-1.0.3.GA-redhat-1.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
The solution is to leave only one.
More details: