SLF4J Overview
The Simple Logging Facade for Java (SLF4J) serves as a simple facade or abstraction for various logging frameworks, such as java.util.logging, logback and log4j. SLF4J allows the end-user to plug in the desired logging framework at deployment time.
Simple Logging Facade for Java
Abstract or simple appearance (the SLF4J) frame may be used as various logs, for examplejava.util.logging
,logback
andlog4j
.SLF4J
The logging framework allows the end user to insert the required deployment.
Binding with a logging framework at deployment time
The SLF4J
distribution ships with several jar files referred to as SLF4J bindings
, with each binding corresponding to a supported framework.
-
slf4j-log4j12-1.7.27.jar
Binding for
log4j version 1.2
, a widely used logging framework. You also need to placelog4j.jar
on your class path. -
slf4j-jdk14-1.7.27.jar
Binding for
java.util.logging
, also referred to as JDK 1.4 logging -
slf4j-nop-1.7.27.jar
Binding for NOP, silently discarding all logging.
-
slf4j-simple-1.7.27.jar
Binding for Simple implementation, which outputs all events to System.err. Only messages of level INFO and higher are printed. This binding may be useful in the context of small applications.
-
slf4j-jcl-1.7.27.jar
Binding for
Jakarta Commons Logging
. This binding will delegate all SLF4J logging to JCL. -
logback-classic-1.2.3.jar (requires logback-core-1.2.3.jar)
There are also SLF4J bindings external to the SLF4J project,
Logback's ch.qos.logback.classic.Logger
class is a direct implementation of SLF4J'sorg.slf4j.Logger
interface.
To switch logging frameworks, just replace slf4j bindings on your class path. For example, to switch from java.util.logging to log4j, just replace slf4j-jdk14-1.7.27.jar with slf4j-log4j12-1.7.27.jar.
To switch logging framework, slf4j simply replace the classpath binding. For example, to switch from log4j java.util.logging, simply replace slf4j-jdk14-1.7.27.jar as slf4j-log4j12-1.7.27.jar can.
SLF4J does not rely on any special class loader machinery. In fact, each SLF4J binding is hardwired at compile time to use one and only one specific logging framework. For example, the slf4j-log4j12-1.7.27.jar binding is bound at compile time to use log4j. In your code, in addition to slf4j-api-1.7.27.jar, you simply drop one and only one binding of your choice onto the appropriate class path location. Do not place more than one binding on your class path.
Consolidate logging via SLF4J (by SLF4J consolidated logging)
SLF4J caters for this common use-case by providing bridging modules for JCL, java.util.logging and log4j.
By providing a bridge module SLF4J JCL, java.util.logging log4j and to meet this common use cases.
Mapped Diagnostic Context (MDC) support
Mapped Diagnostic Context
is essentially a map maintained by the logging framework where the application code provides key-value pairs which can then be inserted by the logging framework in log messages. MDC
data can also be highly helpful in filtering messages or triggering certain actions.
Mapping the diagnostic context is essentially maintained by the log frame mapping, wherein the application code provides key-value pairs, then the logging framework log message may insert pairs. MDC data is also useful in certain filtering operation or triggering message.
SLF4J
supports MDC
, or mapped diagnostic context. If the underlying logging framework offers MDC
functionality, then SLF4J
will delegate to the underlying framework's MDC. Note that at this time, only log4j
and logback
offer MDC
functionality. If the underlying framework does not offer MDC
, for example java.util.logging
, then SLF4J
will still store MDC
data but the information therein will need to be retrieved by custom user code.
SLF4J support MDC or mapped diagnostic context. If the underlying logging framework provides the MDC function, then SLF4J will be entrusted to the underlying framework of the MDC. Please note that currently provide only MDC logback log4j and function. If the underlying framework does not provide a MDC, the java.util.logging e.g., the MDC SLF4J data will still be stored, but the information needs to be retrieved by a custom user code.
Principle Analysis
By the figure shows SLF4J
can be abstract various specific logging framework is StaticLoggerBinder
completed class. Next, look at the focus bind()
method is how to find the StaticLoggerBinder
class source code as follows:
private final static void bind() {
try {
// 查找类路径下所有的StaticLoggerBinder类
Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
// 如果存在多个StaticLoggerBinder类,则打印日志
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
// 获取StaticLoggerBinder实例,如果不存在,则抛出NoClassDefFoundError异常
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
// 打印实际使用StaticLoggerBinder类
reportActualBinding(staticLoggerBinderPathSet);
fixSubstitutedLoggers();
} catch (NoClassDefFoundError ncde) {
String msg = ncde.getMessage();
if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
} else {
failedBinding(ncde);
throw ncde;
}
} catch (java.lang.NoSuchMethodError nsme) {
String msg = nsme.getMessage();
if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {
INITIALIZATION_STATE = FAILED_INITIALIZATION;
Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
Util.report("Your binding is version 1.5.5 or earlier.");
Util.report("Upgrade your binding to version 1.6.x.");
}
throw nsme;
} catch (Exception e) {
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e);
}
}
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
private static Set<URL> findPossibleStaticLoggerBinderPathSet() {
Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration<URL> paths;
if (loggerFactoryClassLoader == null) {
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
URL path = (URL) paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
} catch (IOException ioe) {
Util.report("Error getting resources from path", ioe);
}
return staticLoggerBinderPathSet;
}
复制代码
SLF4J integrated with logback
-
maven dependencies as follows:
<!-- slf4j-api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <!-- logback --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.3</version> </dependency> <!-- logback-classic(已含有对slf4j的集成包) --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.3</version> </dependency> 复制代码
-
Write logback profile logback.xml, reads as follows:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT" /> </root> </configuration> 复制代码
-
Use
private static final Logger logger=LoggerFactory.getLogger(LogbackTest.class); public static void main(String[] args){ if(logger.isDebugEnabled()){ logger.debug("slf4j-logback debug message"); } if(logger.isInfoEnabled()){ logger.info("slf4j-logback info message"); } if(logger.isTraceEnabled()){ logger.trace("slf4j-logback trace message"); } } 复制代码
-
org.slf4j.impl.StaticLoggerBinder
Class implementation
SLF4J integrated with log4
-
maven dependencies as follows:
<!-- slf4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> <!-- slf4j-log4j --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.12</version> </dependency> <!-- log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> 复制代码
-
Write log4j.properties configuration file into the class path
log4j.rootLogger = debug, console log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} %m%n 复制代码
-
Use
private static Logger logger=LoggerFactory.getLogger(Log4j2Slf4jTest.class); public static void main(String[] args){ if(logger.isTraceEnabled()){ logger.trace("slf4j-log4j2 trace message"); } if(logger.isDebugEnabled()){ logger.debug("slf4j-log4j2 debug message"); } if(logger.isInfoEnabled()){ logger.info("slf4j-log4j2 info message"); } } 复制代码
-
org.slf4j.impl.StaticLoggerBinder
Class implementation
Reference material
Integrated Principles jcl and jul, log4j1, log4j2, logback of