Java日誌體系(四)slf4j

 

1.1 簡介

                    

與commons-logging相同,slf4j也是一個通用的日誌接口,在程序中與其餘日誌框架結合使用,並對外提供服務。java

Simple Logging Facade for Java簡稱 slf4j,Java簡單日誌門面系統。在咱們的代碼中,不須要顯式指定具體日誌框架(例如:java.util.logging、logback、log4j),而是使用slf4j的API來記錄日誌即可,最終日誌的格式、記錄級別、輸出方式等經過具體日誌框架的配置來實現,所以能夠在應用中靈活切換日誌系統。mysql

若是你對上面所說的,仍然不太理解。那麼,簡單的說slf4j能夠理解爲JDBC,都是提供接口服務,只不過比JDBC更爲直觀、簡單些。在程序中,JDBC須要單獨指定具體的數據庫實現(例如:mysql),而slf4j並不須要。spring

接下來,咱們講解下關於slf4j具體的使用。sql

 

1.2 slf4j結構

              

上面的截圖,展現的是slf4j搭配log4j使用。數據庫

Logger:slf4j日誌接口類,提供了trace < debug < info < warn < error這5個級別對應的方法,主要提供了佔位符{}的日誌打印方式;apache

Log4jLoggerAdapter:Logger適配器,主要對org.apache.log4j.Logger對象的封裝,佔位符{}日誌打印的方式在此類中實現;api

LoggerFactory:日誌工廠類,獲取實際的日誌工廠類,獲取相應的日誌實現對象;app

lLoggerFactory:底層日誌框架中日誌工廠的中介,再其實現類中,經過底層日誌框架中的日誌工廠獲取對應的日誌對象;框架

StaticLoggerBinder:靜態日誌對象綁定,在編譯期肯定底層日誌框架,獲取實際的日誌工廠,也就是lLoggerFactory的實現類;性能

 

1.3 使用

同爲Java日誌接口框架,相對於commons-logging來講,slf4j的使用有點特殊。

commons-logging無需在pom.xml文件中單獨引入日誌實現框架,即可進行日誌打印。可是,slf4j並不支持此功能,必須在pom.xml中單獨引入底層日誌實現。

 

【SLF4J + log4j】使用:
須要在pom.xml文件中添加依賴:

//slf4j:
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.20</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>

聲明測試代碼:

import org.slf4j.Logger; import org.slf4j.LoggerFactory; /**** ** SLF4J **/ public class Slf4jLog { final static Logger logger = LoggerFactory.getLogger(Slf4jLog.class); public static void main(String[] args) { logger.trace("Trace Level."); logger.info("Info Level."); logger.warn("Warn Level."); logger.error("Error Level."); } }

接下來,在classpath下定義配置文件:log4j.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' >
    <appender name="myConsole" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d{dd HH:mm:ss,SSS\} %-5p] [%t] %c{2\} - %m%n" />
        </layout>
        <!--過濾器設置輸出的級別-->
        <filter class="org.apache.log4j.varia.LevelRangeFilter">
            <param name="levelMin" value="debug" />
            <param name="levelMax" value="error" />
            <param name="AcceptOnMatch" value="true" />
        </filter>
    </appender>

    <!-- 根logger的設置-->
    <root>
        <priority value ="debug"/>
        <appender-ref ref="myConsole"/>
    </root>
</log4j:configuration>

咱們仍是用上面的代碼,無需作改變,運行結果爲:

[15 16:04:06,371 DEBUG] [main] slf4j.SLF4JLog - Debug Level. [15 16:04:06,371 INFO ] [main] slf4j.SLF4JLog - Info Level. [15 16:04:06,371 WARN ] [main] slf4j.SLF4JLog - Warn Level. [15 16:04:06,371 ERROR] [main] slf4j.SLF4JLog - Error Level.

 

【SLF4J + JDKLog】使用:
須要在pom.xml文件中添加依賴:
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.21</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-jdk14</artifactId>
  <version>1.7.21</version>
</dependency>

咱們仍是用上面的代碼,無需作改變,運行結果爲:

七月 15, 2016 3:30:02 下午 com.chanshuyi.slf4j.Slf4jJDKLog main 信息: Info Level. 七月 15, 2016 3:30:02 下午 com.chanshuyi.slf4j.Slf4jJDKLog main 警告: Warn Level. 七月 15, 2016 3:30:02 下午 com.chanshuyi.slf4j.Slf4jJDKLog main 嚴重: Error Level.

 

【SLF4J + LogBack】使用:
須要在pom.xml文件中添加依賴:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.21</version>
</dependency>
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.1.7</version>
</dependency>
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-core</artifactId>
  <version>1.1.7</version>
</dependency>

配置 logback.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
        </layout>
    </appender>
    <logger name="com.chanshuyi" level="TRACE"/>

    <root level="warn">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

咱們仍是用上面的代碼,無需作改變,運行結果爲:

16:08:01.040 [main] TRACE com.chanshuyi.slf4j.SLF4JLog - Trace Level. 16:08:01.042 [main] DEBUG com.chanshuyi.slf4j.SLF4JLog - Debug Level. 16:08:01.043 [main] INFO  com.chanshuyi.slf4j.SLF4JLog - Info Level. 16:08:01.043 [main] WARN  com.chanshuyi.slf4j.SLF4JLog - Warn Level. 16:08:01.043 [main] ERROR com.chanshuyi.slf4j.SLF4JLog - Error Level.

 

對於slf4j來講,它只提供了一個核心模塊--slf4j-api,這個模塊下只有日誌接口,沒有具體的實現,因此在實際開發總須要單獨添加底層日誌實現。可是,這些底層日誌類實際上跟slf4j並無任何關係,所以slf4j又經過增長一層日誌中間層來轉換相應的實現,例如上文中的slf4j-log4j12。
 
        
  • 具體的接入方式參見下圖
        •    

上圖,是官方文檔中slf4j與其餘日誌框架相結合的使用狀況,具體總結以下:

logback:logback-classic 、logback-core java.util.logging.Logging:slf4j-jdk14 commons-logging:jcl-over-slf4j

其中,commons-logging比較特殊。因爲commons-logging誕生的比較早,一些年限久遠的系統大致上都使用了commons-logging和log4j的日誌框架組合,大名鼎鼎的spring框架也依然在使用commons-logging框架。那麼,此時你的新系統若是想使用slf4j該如何處理?

這會,就須要引入jcl-over-slf4j.jar包了,它會將commons-logging的「騙入」到slf4j中來,實現日誌框架結合;

 

1.4 slf4j靜態綁定原理

雖然commons-logging和slf4j都是日誌服務接口,可是二者對於底層日誌框架綁定的方式相差甚遠。在第一篇日誌系統的文章中,筆者已經介紹過,commons-logging是基於動態綁定來實現與日誌框架的結合,也就是說在編譯期間咱們的程序並不知道底層的實現是什麼,只有在運行期間才進行獲取;

與commons-logging不一樣的是,slf4j是基於靜態綁定來實現與日誌框架的結合,在編譯期間咱們的程序就已經知道使用了哪一種日誌實現。


1.5 slf4j和commons-logging比較

(1)slf4j使用了靜態綁定方式,實現了與底層日誌框架的結合, 避免了commons-logging中因爲類加載器不一樣致使的日誌加載失敗狀況的發生;

(2)slf4j支持參數化日誌打印,也就是佔位符{}的方式。去除了commons-logging中的isDebugEnabled(), isInfoEnabled()等方法的日誌級別檢查代碼,極大的提升了代碼可讀性;而且,佔位符的方式也延緩了構建日誌信息(String的開銷),提升了內存的使用性;

在commons-logging中,咱們常常須要些這樣的代碼:

if (logger.isDebugEnabled()) { logger.debug("我是: " + name); }

而在slf4j中,咱們能夠這樣寫:

logger.debug("我是: {}",name);

在commons-logging中,是要符合日記級別,咱們就進行字符串的拼接;而在slf4j中,咱們不進行字符串拼接操做,而是使用StringBuffer來完成的替換。這不只下降了內存消耗並且預先下降了CPU去處理字符串鏈接命令的時間,提升了程序的性能。

 

1.6 slf4j搭配commons-logging使用原理

在前面的小節中,咱們提到了slf4j爲了兼容老代碼,是能夠跟commons-logging結合使用的,須要在pom.xml文件中引入jcl-over-slf4j.jar包。具體實現過程以下:

測試代碼:(引入的依舊爲commons-logging對象,無需改變)

import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Test; public class commons_loggingDemo { Log log= LogFactory.getLog(commons_loggingDemo.class); @Test public void test() throws IOException { log.debug("Debug info."); log.info("Info info"); log.warn("Warn info你好"); log.error("Error info"); log.fatal("Fatal info"); } }

引入pom依賴:(除了原有的commons-logging和log4j依賴外,還須要添加slf4j-api、jcl-over-slf4j、slf4j-log4j12依賴)

!-- commons-logging -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.3</version>
</dependency>

<!--將commons-logging引入到slf4j中去-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.20</version>
</dependency>

 <!--log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<!--slf4j-log4j -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.12</version>
</dependency>

 <!--slf4j -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.20</version>
</dependency>

日誌配置文件: (均爲commons-logging時期配置,無需爲slf4j作任何改變)

commons-logging.properties配置文件: #日誌對象: org.apache.commons.logging.Log=org.apache.log4j.Logger #日誌工廠: org.apache.commons.logging.LogFactory=org.apache.commons.logging.impl.LogFactoryImpl log4j.xml配置文件: <log4j:configuration>
    <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <param name="ImmediateFlush" value="true"/>
        <param name="encoding" value="UTF-8"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %t %-5p (%c:%L) - %m%n"/>
        </layout>
    </appender>
    <root>
        <priority value="debug" />
        <appender-ref ref="CONSOLE" />
    </root>
</log4j:configuration>

實現原理:

將commons-logging的輸出引入到jcl-over-slf4j中,再轉向slf4j,緊接着進入到slf4j-log4j12,最終進入到log4j;
參考:https://www.jianshu.com/p/e3b2de9e418b
相關文章
相關標籤/搜索