關於log4j、jul、jcl、slf4j等等日誌組件的理解

日誌組件:

  我們經常在開發項目的時候,需要打印記錄項目過程中的一些日誌。那我們經常大概會用到 log4j、jul、jcl、slf4j、simple、nop、logback 等等,那我們就詳細介紹下這些組件是怎麼做日誌打印的

JUL:

JUL全稱Java util Logging是java原生的日誌框架,使用時不需要另外引用第三方類庫,相對其他日誌框架使用方便,學習簡單,能夠在小型應用中靈活使用。
架構介紹:

             

  

  Loggers :被稱為記錄器,應用程序通過獲取Logger對象,調用其API來發佈日誌信息。Logger通常為應用程序訪問日誌系統的入口程序。
  Appenders :也被稱為Handlers,每個Logger都會關聯一組Handlers,Logger會將日誌交給關聯Handlers處理,由Handlers負責將日誌做記錄。Handlers在此是一個抽象,其具體的實現決定了日誌記錄的位置可以是控制台、文件、網絡上的其他日誌服務或操作系統日          志等。
  Layouts :也被稱為Formatters,它負責對日誌事件中的數據進行轉換和格式化。Layouts決定了數據在一條日誌記錄中的最終形式。
  Level :每條日誌消息都有一個關聯的日誌級別。該級別粗略指導了日誌消息的重要性和緊迫,我可以將Level和Loggers,Appenders做關聯以便於我們過濾消息。
  Filters :過濾器,根據需要定製哪些信息會被記錄,哪些信息會被放過。

  總結:
    用戶使用Logger來進行日誌記錄,Logger持有若干個Handler,日誌的輸出操作是由Handler完成的。
    在Handler輸出日誌前,會經過Filter的過濾,判斷哪些日誌級別過濾放行哪些攔截,
    Handler會將日誌內容輸出到指定位置(日誌文件、控制台等)。Handler在輸出日誌時會使用Layout,將輸出內容進行排版

   案例: 

public class JULTest {

    @Test
    public void test01() {
        // 1.獲取日誌記錄器對象
        Logger logger = Logger.getLogger("jul");
        // 2.日誌記錄輸出
        logger.info("jul");
    }
} 

日誌的級別:

  jul中定義的日誌級別

    java.util.logging.Level中定義了日誌的級別:
      SEVERE(最高值)
      WARNING  警告信息
      INFO (默認級別)
      CONFIG  配置信息
      FINE  debug級別信息,信息顆粒度最小
      FINER  debug級別信息
      FINEST(最低值)debug級別信息,信息顆粒度最大
    還有兩個特殊的級別:
      OFF,可用來關閉日誌記錄。
      ALL,啟用所有消息的日誌記錄。

日誌級別案例:

@Test
public void testLogLevel() {
    // 1.獲取日誌對象
    Logger logger = Logger.getLogger("jul");
    // 2.日誌記錄輸出
    logger.severe("severe");
    logger.warning("warning");
    logger.info("info");
    logger.config("config");
    logger.fine("fine");
    logger.finer("finer");
    logger.finest("finest");
}

  由於默認級別是info, 所以以上日誌只會打印 info以上級別的日誌

修改日誌級別:

@Test
public void testLogConfig() throws IOException {
    // 1.創建日誌記錄器對象
    Logger logger = Logger.getLogger("jul");

    // 一、自定義日誌級別
    // a.關閉系統默認配置
    logger.setUseParentHandlers(false);
    // b.創建handler對象
    ConsoleHandler consoleHandler = new ConsoleHandler();
    // c.創建formatter對象(簡單格式轉換對象)
    SimpleFormatter simpleFormatter = new SimpleFormatter();
    // d.進行關聯
    consoleHandler.setFormatter(simpleFormatter);
    logger.addHandler(consoleHandler);
    // e.設置日誌級別
    logger.setLevel(Level.FINE);
    consoleHandler.setLevel(Level.FINE);

    // 二、輸出到日誌文件
    FileHandler fileHandler = new FileHandler("d:/jul.log");
    fileHandler.setFormatter(simpleFormatter);

    logger.addHandler(fileHandler);
    // 2.日誌記錄輸出
    logger.severe("severe");
    logger.warning("warning");
    logger.info("info");
    logger.config("config");
    logger.fine("fine");
    logger.finer("finer");
    logger.finest("finest");
}

 

JCL:

JCL全稱為Jakarta Commons Logging,是Apache提供的一個通用日誌API。
  它是為 “所有的Java日誌實現”提供一個統一的接口,它自身也提供一個日誌的實現,但是功能非常弱(SimpleLog)。所以一般不會單獨使用它。
  他允許開發人員使用不同的具體日誌實現工具: Log4j, Jdk自帶的日誌(JUL)
  JCL 有兩個基本的抽象類:Log(基本記錄器)和LogFactory(負責創建Log實例)。

  默認使用 jul 的實現

 

   案例:

    1.添加依賴

  

  <dependencies>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

    2. 測試

public class JCLTest {

    @Test
    public void test() {
        // 創建日誌對象
        Log log = LogFactory.getLog("jcl");
        // 日誌記錄輸出
        log.info("info");
    }
}

  

JCL原理:

  1. 通過LogFactory動態加載Log實現類

     

   2 . 日誌門面支持的日誌實現數組

    

   3 . 獲取具體的日誌實現

    

LOG4J:

  Log4j是Apache下的一款開源的日誌框架,通過在項目中使用 Log4J,我們可以控制日誌信息輸出到控制台、文件、甚至是數據庫中。我們可以控制每一條日誌的輸出格式,通過定義日誌的輸出級別,可以更靈活的控制日誌的輸出過程。方便項目的調試

  log4j.properties(最簡單配置)

log4j.rootLogger=INFO,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n

  案例:

  1. 添加依賴

    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

  2. 測試

@Test
public void test01() {
    // 獲取日誌記錄器對象
    Logger logger = Logger.getLogger(Log4jTest.class);
    // 日誌記錄輸出
    logger.info("hello log4j");

    // 日誌測試
    logger.info("info");
}

  

日誌的級別:

  每個Logger都有一個日誌級別(log level),用來控制日誌信息的輸出。日誌級別從高到低分為:
    fatal 指出每個嚴重的錯誤事件將會導致應用程序的退出。
    error 指出雖然發生錯誤事件,但仍然不影響系統的繼續運行。
    warn 表明會出現潛在的錯誤情形。
    info 一般和在粗粒度級別上,強調應用程序的運行全程。
    debug 一般用於細粒度級別上,對調試應用程序非常有幫助。(默認級別)
    trace 是程序追蹤,可以用於輸出程序運行中的變量,顯示執行的流程。
  還有兩個特殊的級別:
    OFF,可用來關閉日誌記錄。
    ALL,啟用所有消息的日誌記錄。

  註:一般只使用 4個級別,優先級從高到低為 ERROR > WARN > INFO > DEBUG

slf4j: 

  簡單日誌門面(Simple Logging Facade For Java) SLF4J主要是為了給Java日誌訪問提供一套標準、規範的API框架,其主要意義在於提供接口,具體的實現可以交由其他日誌框架,例如log4j和logback等。當然slf4j自己也提供了功能較為簡單的實現,但是一般很少用到。對於一般的Java項目而言,日誌框架會選擇slf4j-api作為門面,通過綁定器綁定具體的實現框架(log4j、logback等)進行日誌打印,與第三方其它框架統一日誌的時候,中間使用橋接器完成橋接。
SLF4J是目前市面上最流行的日誌門面。現在的項目中,基本上都是使用SLF4J作為日誌系統。
SLF4J日誌門面主要提供兩大功能:

  1. 日誌框架的綁定
  2. 日誌框架的橋接

  入門案例:

  1. 添加依賴  

    <dependencies>
        <!--slf4j core 使用slf4j必須添加-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.26</version>
        </dependency>
        <!--slf4j 自帶的簡單日誌實現 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.27</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

  2. 測試

public class Slf4jTest {

    // 聲明日誌對象
    public final static Logger LOGGER = 
     LoggerFactory.getLogger("slf4j");

    @Test
    public void test01() {
        //打印日誌信息
        LOGGER.info("info");
    }
}        

  

綁定日誌的實現(Binding):

  SLF4J支持各種日誌框架。SLF4J發行版附帶了幾個稱為「SLF4J綁定」的jar文件,每個綁定對應一個受支持的框架。

  使用slf4j的日誌綁定流程:
    1. 添加slf4j-api的依賴
    2. 使用slf4j的API在項目中進行統一的日誌記錄
    3. 綁定具體的日誌實現框架
      1. 綁定已經實現了slf4j的日誌框架,直接添加對應依賴
      2. 綁定沒有實現slf4j的日誌框架,先添加日誌的適配器,再添加實現類的依賴
    4. slf4j有且僅有一個日誌實現框架的綁定(如果出現多個默認使用第一個依賴日誌實現)

  通過maven引入常見的日誌實現框架:(根據實際情況選擇使用,除了引入下面其中一個,還不能少了 slf4j-api 的引用)

  官方綁定器API地址: //www.slf4j.org/manual.html

  1. logback

<!-- logback 日誌實現 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

  2. nop

<!-- nop 日誌開關(不使用日誌功能) -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-nop</artifactId>
    <version>1.7.2</version>
</dependency>

  3. log4j

<!-- 綁定 log4j 日誌實現,需要導入適配器,還需要添加 log4j.properties 配置文件 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.26</version>
</dependency>
<!-- log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

  4. jul

<!-- 綁定 jul 日誌實現,需要導入適配器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-jdk14</artifactId>
    <version>1.7.25</version>
</dependency>
<!-- 因為是java原生的日誌框架,已經內置了具體實現 -->

  原理:

 

 

 

 

橋接其它框架日誌的實現(Bridging):

  橋接解決的是項目中日誌的遺留問題,當系統中存在之前的日誌API,可以通過橋接轉換到slf4j的實現

    1. 先去除之前老的日誌框架的依賴
    2. 添加SLF4J提供的橋接組件
    3. 為項目添加SLF4J的具體實現

    4. 統一應用和框架的日誌實現

  遷移的方式:

    如果我們要使用SLF4J的橋接器,替換原有的日誌框架,那麼我們需要做的第一件事情,就是刪除掉原有項目中的日誌框架的依賴。然後替換成SLF4J提供的橋接器。

  官方api地址: //www.slf4j.org/legacy.html

原理:

 

 

 

 

   1. log4j

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>
<!-- 配置 log4j 的橋接器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>

  2. logback

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>
<!-- 配置 log4j 的橋接器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>
<!-- logback 日誌實現 -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

  3. jcl

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>
<!-- 配置 jcl 的橋接器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.7.8</version>
</dependency>

  4. jul

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.26</version>
</dependency>
<!-- 配置 jul 的橋接器 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
    <version>1.7.25</version>
</dependency>

  註:    

    1. jcl-over-slf4j.jar(橋接)和 slf4j-jcl.jar(適配)不能同時部署。前一個jar文件將導致JCL將日誌系統的選擇委託給SLF4J,後一個jar文件將導致SLF4J將日誌系統的選擇委託給JCL,從而導致無限循環 。

    2. log4j-over-slf4j.jar和slf4j-log4j12.jar不能同時出現,原因同上

    3 . jul-to-slf4j.jar和slf4j-jdk14.jar不能同時出現,原因同上

    4. 所有的橋接都只對Logger日誌記錄器對象有效,如果程序中調用了內部的配置類或者是Appender,Filter等對象,將無法產生效果。