SLF4J概述
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
(SLF4J)可用作各種日誌框架的簡單外觀或抽象,例如java.util.logging
,logback
和log4j
。SLF4J
允許終端使用者在部署時插入所需的日誌記錄框架。
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.
要切換日誌框架,只需替換類路徑上的slf4j繫結。例如,要從java.util.logging切換到log4j,只需將slf4j-jdk14-1.7.27.jar替換為slf4j-log4j12-1.7.27.jar即可。
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(通過SLF4J整合日誌記錄)
SLF4J caters for this common use-case by providing bridging modules for JCL, java.util.logging and log4j.
SLF4J通過為JCL,java.util.logging和log4j提供橋接模組來滿足這種常見用例。
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.
對映診斷上下文字質上是由日誌框架維護的對映,其中應用程式程式碼提供鍵值對,然後日誌訊息中的日誌記錄框架可以插入鍵值對。 MDC資料在過濾訊息或觸發某些操作方面也非常有用。
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支援MDC或對映診斷上下文。 如果底層日誌記錄框架提供了MDC功能,那麼SLF4J將委託給底層框架的MDC。 請注意,目前只有log4j和logback提供MDC功能。 如果底層框架不提供MDC,例如java.util.logging,則SLF4J仍將儲存MDC資料,但其中的資訊需要由自定義使用者程式碼檢索。
原理分析
通過上圖可知SLF4J
能夠抽象各種具體日誌框架,是由StaticLoggerBinder
類完成。接下來重點看看bind()
方法是如何查詢StaticLoggerBinder
類,原始碼如下:
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與logback整合
-
maven依賴包如下:
<!-- 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> 複製程式碼
-
編寫logback的配置檔案logback.xml,內容如下:
<?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> 複製程式碼
-
使用方式
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
類實現
SLF4J與log4整合
-
maven依賴包如下:
<!-- 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> 複製程式碼
-
編寫log4j.properties配置檔案,放到類路徑下
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 複製程式碼
-
使用方式
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
類實現