Log4j2的使用,以及Spring 和 SpringBoot 分別使用Slf4j集成Log4j2構建項目日誌系統

一、日誌框架介紹

        Slf4j(全稱是Simple Loging Facade For Java) 是一個爲Java程序提供日誌輸出的統一接口,是對所有日誌框架制定的一種規範、標準、接口,並不是一個具體的日誌實現方案,因此Slf4j並不能但單獨使用,需要和其他具體的日誌框架實現配合使用,比如log4j、logback、log4j2等。

        Log4j2是Log4j 1.x和Logback的改進版,它相比其前身Log4j 1.x進行了重大改進,並提供了Logback中可用的許多改進,吸取了優秀的Logback的設計而重新推出的一款新組件,同時修復了Logback架構中的一些固有問題。 從GitHub的更新日誌來看,Logback更新活躍度一般,而作爲知名組織的Apache下的Log4j2的更新卻是非常活躍的,並且流行度也很高,Log4j 1.x 於2015年8月停止維護更新了。

       Log4j2官方網址:http://logging.apache.org/log4j/2.x/

 

二、爲什麼需要用Slf4j接口集成Log4j2,而不直接使用其具體實現的Log4j2

        Slf4j接口是一個爲Java程序提供日誌輸出的統一接口,是對所有日誌框架制定的一種規範、標準、接口,可以有多個實現,使用時是面向接口的 (導入的包都是slf4j的包而不是具體某個日誌框架中的包),即直接和接口交互,不直接使用具體實現,所以可以任意的更換具體實現而不用更改代碼中的日誌相關代碼,這就可以很好的保證我們的日誌系統具有良好的兼容性,能夠兼容當前常見的幾種日誌系統,同時使用log4j2而不是log4j是因爲Log4j 1.x 在高併發情況下出現死鎖導致cpu使用率異常飆升,而Log4j2.0基於LMAX Disruptor的異步日誌在多線程環境下性能會遠遠優於Log4j 1.x和logback (官方數據是10倍以上)。

 

三、Log4j2的簡單使用

1、在pom.xml文件中引入Log4j2的依賴

<properties>
     <log4j.version>2.11.1</log4j.version>
</properties>

<dependencies>

  <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
      <version>${log4j.version}</version>
  </dependency>

  <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>${log4j.version}</version>
  </dependency>

</dependencies>

 

2、編寫Log4j2Test測試類,進行簡單測試

package com.log4j2.test;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


public class Log4j2Test {

    //通過根日誌名稱來獲取日誌實例
    private static final Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);

    public static void main(String[] args) {

        logger.trace("trace level");
        logger.debug("debug level");
        logger.info("info level");
        logger.warn("warn level");
        logger.error("error level");
        logger.fatal("fatal level");
    }

}

 

3、其運行結果如下所示

2019-08-17 11:19:11,993 main WARN No Root logger was configured, creating default ERROR-level Root logger with Console appender
11:19:12.118 [main] ERROR  - error level
11:19:12.118 [main] FATAL  - fatal level

結果說明:

     1、在項目中,我們只引入了Log4j2的依賴包並沒有引入或者編寫其相應的配置文件,在控制檯輸出了第一句,其解釋爲:沒有配置根記錄程序,使用控制檯附加程序創建默認的錯誤級根記錄程序

     2、可以看到控制檯只輸出了error 和 fatal級別的錯誤信息,其他級別的錯誤信息並沒有被輸出,是因爲沒有配置文件,則默認使用error級別並在控制檯輸出,所以只有error 或者比 error更高的級別 fatal被輸出到控制檯

    3、缺省的配置等同於如下其默認的配置 (相關配置會在後面進行統一講解)

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">

    <Appenders>
       <Console name="Console" target="SYSTEM_OUT">
           <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
       </Console>
    </Appenders>

    <Loggers>
        <Root level="error">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

 

四、Log4j2的日誌名稱層次輸出規則

1、在com.log4j2包路徑下創建一個名爲Log4j2類

package com.log4j2;


import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Log4j2 {

    private static final Logger logger = LogManager.getLogger(Log4j2.class);

    public static void main(String[] args) {

        logger.info("INFO:Log4j2 --- info level");
        logger.warn("WARN:Log4j2 --- warn level");
        logger.error("ERROR:Log4j2 --- error level");
    }
}

 

2、在src/main/resources目錄下,創建一個名爲log4j2.xml的配置文件 (注意:配置文件的名稱最好爲log4j2.xml,因爲log4j2默認會去找一個名爲log4j2.xml的配置文件)

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">

    <Appenders>
       <Console name="Console" target="SYSTEM_OUT">
           <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
       </Console>
    </Appenders>
    <Loggers>
        <Logger name="com.log4j2.Log4j2" level="info">
            <AppenderRef ref="Console"/>
        </Logger>

        <Logger name="com.log4j2" level="warn">
            <AppenderRef ref="Console"/>
        </Logger>

        <Root level="error">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

 

3、其運行結果如下所示

14:13:47.526 [main] INFO  com.log4j2.Log4j2 - INFO:Log4j2 --- info level
14:13:47.526 [main] INFO  com.log4j2.Log4j2 - INFO:Log4j2 --- info level
14:13:47.526 [main] INFO  com.log4j2.Log4j2 - INFO:Log4j2 --- info level
14:13:47.529 [main] WARN  com.log4j2.Log4j2 - WARN:Log4j2 --- warn level
14:13:47.529 [main] WARN  com.log4j2.Log4j2 - WARN:Log4j2 --- warn level
14:13:47.529 [main] WARN  com.log4j2.Log4j2 - WARN:Log4j2 --- warn level
14:13:47.529 [main] ERROR com.log4j2.Log4j2 - ERROR:Log4j2 --- error level
14:13:47.529 [main] ERROR com.log4j2.Log4j2 - ERROR:Log4j2 --- error level
14:13:47.529 [main] ERROR com.log4j2.Log4j2 - ERROR:Log4j2 --- error level

結果說明:

     1、在控制檯中,我們可以看到,同樣的日誌信息被輸出了三次,細心的小夥伴們就會發現,名爲"com.log4j2.Log4j2"的子級Logger的level=info,而名爲"com.log4j2"的父級Logger的level=warn 和 頂級Root的level=error,都比子級Logger的level級別要高,那爲什麼低級別的信息,例如:info信息,還會被父級Logger 和 頂級Root輸出打印呢?這是因爲<Logger>標籤中的additivity默認爲true,即允許同時輸出日誌到父級的Appender中。同時Logger的命名符合命名層次規則,即一個Logger的名稱是另一個Logger名稱的前綴,則稱其爲另一個Logger的祖先或者父級,例如:名爲com.log4j2的Logger 是名爲com.log4j2.Log4j2的Logger的祖先或者父級

     2、同時Logger的命名和類的命名也有關聯,當我們在配置文件中配置一個名爲com.log4j2.Log4j2的Logger,那麼在com.log4j2.Log4j2類中的Logger就會匹配到這一配置

    3、Root是整個命名層次規則的頂層,所以在輸出日誌時,配置文件中的二個Logger 和 Root對應的Appender會分別被調用

    4、如果你不想日誌輸出到父級的Appender中,則在<Logger>標籤中配置additivity="false"即可

 

4、修改名爲"com.log4j2.Log4j2"的Logger的level,由info 修改爲 error,其他配置不變

<Logger name="com.log4j2.Log4j2" level="error">
   <AppenderRef ref="Console"/>
</Logger>

 

5、其運行結果如下所示

09:41:42.127 [main] ERROR com.log4j2.Log4j2 - ERROR:Log4j2 --- error level
09:41:42.127 [main] ERROR com.log4j2.Log4j2 - ERROR:Log4j2 --- error level
09:41:42.127 [main] ERROR com.log4j2.Log4j2 - ERROR:Log4j2 --- error level

結果說明:

    1、在控制檯中,我們可以看到,日誌信息只有error級別的被輸出了三次,而info 和 warn級別的信息並沒有在子級Logger、父級Logger 和 頂級Root中被輸出打印,這又是爲什麼呢?首先info 和 warn級別的信息並沒有在子級Logger中被打印,我們可以理解,這是因爲我們修改了子級Logger的level=error,所以低於error級別的信息,將不會被子級Logger所打印

    2、父級Logger的level=warn,頂級Root的level=error,那麼至少warn級別的信息應該被父級Logger輸出打印纔對啊,可是爲什麼並沒有被打印呢?這是因爲子級Logger的level=error,只有被子級Logger輸出打印的信息,纔會被父級Logger 和 頂級Root輸出打印

 

五、Log4j2的配置文件詳解

1、Log4j2配置文件的名稱以及在項目中的存放位置

  log4j 2.0不再支持像1.x中以".properties"後綴的文件配置方式,2.x版本的配置文件後綴名只能以".xml",".json"或者".jsn"結尾。

  在默認情況下,系統選擇Log4j2配置文件的優先級如下:

classpath路徑下名爲 log4j-test.json 或者log4j-test.jsn文件
classpath路徑下名爲 log4j2-test.xml
classpath路徑下名爲 log4j.json 或者log4j.jsn文件
classpath路徑下名爲 log4j2.xml


這裏就會有人有疑問,classpath路徑在java項目中到底指向哪裏?

   1、src不是classpath,WEB-INF/classes、WEB-INF/lib纔是classpath,WEB-INF/是資源目錄,客戶端不能直接訪問。
   2、WEB-INF/classes目錄用於存放 src目錄下java文件編譯之後的class文件、xml、properties等資源配置文件,這是一個定位資源的入口。
   3、lib和classes同屬classpath,兩者的訪問優先級爲: lib>classes。

 

2、log4j2.xml配置文件的大致結構,如下圖所示

 

3、相關配置介紹

3.1、<Configuration>標籤,根節點

Configuration: 根節點,擁有status 和 monitorInterval等多個屬性
  status屬性:用於控制log4j2日誌框架本身的日誌級別,如果將stratus設置爲較低的級別就會看到很多關log4j2本身的日誌,如加載log4j2配置文件的路徑等信息,其取值有:ALL、TRACE、DEBUG、INFO、WARN、ERROR、FATAL、OFF
 
  monitorInterval屬性:用於指定log4j2每隔多少秒重新讀取配置文件,可以在修改配置時不重啓應用的情況,重新讀取修改後的配置文件

 

3.2、<properties>標籤,用於定義常量

properties:屬性,可包含多個property標籤,用於定義常量,以便在配置其他屬性時引用該常量,properties屬性是可選的,即:可配可不配
  property標籤:用於配置常量
      name:property的屬性,用於在配置其他屬性時引用該常量

 

3.3、<Appenders>標籤,用於定義日誌輸出

Appenders:輸出源,用於定義日誌輸出的地方,log4j2支持的輸出源有很多,常見的有控制檯Console、文件File 和 RollingRandomAccessFile

  Console:用於定義將日誌打印到控制檯上,開發的時候一般都會配置,以便調試
     name屬性:用於指定Console的名稱
     target屬性:取值爲SYSTEM_OUT 或者 SYSTEM_ERR,一般設置爲SYSTEM_OUT即可
     follow屬性:用於標識appender是否通過System.setOut或System.setErr在配置後進行重新分配System.out或System.err
     PatternLayout子節點:用於定義輸出格式和字符集,通過pattern設置輸出格式,charset指定字符集
  
  File:用於定義將日誌輸出到指定的文件中,需要配置輸出到哪個位置,例如:D:/logs/mylog.log
    name屬性:用於指定File的名稱
    fileName屬性:用於指定輸出日誌的目的文件,帶全路徑的文件名,例如:D:/logs/mylog.log
    append屬性:用於指定是否以追加的方式添加日誌到文件中,默認爲true,當設置爲false時,每此輸入日誌都會將之前的文件內容刪除
    PatternLayout子節點:用於定義輸出格式和字符集,通過pattern設置輸出格式,charset指定字符集

  RollingRandomAccessFile:用於定義將日誌輸出到指定的文件中,相比File更加強大,可以指定當文件達到一定大小(如60MB)時,另起一個文件繼續寫入日誌,另起一個文件就涉及到新文件的名字命名規則,因此需要配置文件命名規則,而這種方式更加實用,因爲你不可能一直往一個文件中寫,如果一直寫,文件過大,打開就會卡死,也不便於查找日誌。
    name屬性:用於指定RollingRandomAccessFile的名稱
    fileName屬性:用於指定輸出日誌的目的文件,帶全路徑的文件名,例如:D:/logs/mylog.log
    filePattern屬性:用於指定當發生Rolling時,即新建一個文件繼續寫入日誌時,新建文件的命名規則
    append屬性:用於指定是否以追加的方式添加日誌到文件中,默認爲true,當設置爲false時,每此輸入日誌都會將之前的文件內容刪除
    PatternLayout子節點:用於定義輸出格式和字符集,通過pattern設置輸出格式,charset指定字符集
    Policies子節點:用於指定滾動日誌的策略,即:什麼時候進行新建日誌文件輸出日誌
      TimeBasedTriggeringPolicy:Policies的子節點,基於時間的滾動策略,interval屬性用來指定多久滾動一次,默認是1小時。同時interval屬性需要結合filePattern屬性,如果filePattern屬性的命名規則是%d{yyyy-MM-dd HH-mm}-%i.log,最小的時間粒度是mm,即:分鐘,那麼如果指定interval爲1的話,就是一分鐘生成一個新的文件,如果命名規則改爲%d{yyyy-MM-dd HH}-%i.log,最小的時間粒度是HH,即:小時,那麼如果指定interval爲1的話,就是一小時生成一個新的文件
      SizeBasedTriggeringPolicy:Policies的子節點,基於指定文件大小的滾動策略,size屬性用來定義每個日誌文件的大小.
    DefaultRolloverStrategy子節點:用來指定同一個文件夾下最多保存多少個日誌文件,通過max屬性進行設置
    Filters子節點:用於配置日誌過濾器
       ThresholdFilter:Filters的子節點,閾值(日誌級別) 過濾器
                 level:ThresholdFilter的屬性,用於設置日誌過濾的級別
               onMatch:ThresholdFilter的屬性,默認值是NEUTRAL(中立),其取值有ACCEPT(接受)、DENY(拒絕)、NEUTRAL(中立),onMatch指的是日誌級別大於等於level時的操作
            onMismatch:ThresholdFilter的屬性,默認值是DENY(拒絕),其取值有ACCEPT(接受)、DENY(拒絕)、NEUTRAL(中立),onMismatch表示日誌級別小於level時的操作
                 
                在使用單個過濾器的時候,一般就是使用ACCEPT(接受) 和 DENY(拒絕)這兩個值。但是在組合過濾器中,
             如果用接受ACCEPT(接受)的話,日誌信息就會直接寫入到日誌文件中,後續的過濾器將不再對其進行過濾。
             所以,在組合過濾器中,接受時使用NEUTRAL(中立),被第一個過濾器接受的日誌信息,會繼續使用後面的
             過濾器進行過濾,只有符合所有過濾器條件的日誌信息,最終纔會被寫入到日誌文件中。


  PatternLayout輸出格式介紹:
      %d/%data{yyyy-MM-dd HH:mm:ss.SSS} 表示輸出到毫秒的時間
      %t/%thread 輸出當前線程名稱
      %-5level 輸出日誌級別,-5表示左對齊並且固定輸出5個字符,如果不足在右邊補0
      %logger 輸出logger名稱,因爲Root Logger沒有名稱,所以沒有輸出
      %C/%class 輸出所在類的全路徑名
      %msg 日誌文本
      %n 換行

  其他常用的佔位符有:
      %F 輸出所在的類文件名,如Log4j2.java
      %L 輸出行號
      %M 輸出所在方法名
      %l 輸出語句所在的行數, 包括類名、方法名、文件名、行數

               

 

3.4、<Loggers>標籤,日誌器

Loggers:日誌器,又分爲根日誌器Root 和 自定義日誌器Logger,如果沒有單獨指定Logger 或者 根據日誌名稱獲取不到指定的Logger時,就會使用Root作爲默認的日誌器

  Root:根日誌器 / AsyncRoot:異步根日誌器
    level屬性:用於指定日誌輸出級別,一共有8個級別,按照從低到高爲:all < trace < debug < info < warn < error < fatal < off,不指定level屬性時,默認爲error
    AppenderRef子節點:用於指定日誌輸出到哪個Appender中,通過ref屬性指定
 
  Logger:自定義日誌器 / AsyncLogger:異步自定義日誌器
    name屬性:Logger的名稱,可用包名作爲日誌的名字,不同的包可配置不同的日誌級別
    level屬性:用於指定日誌輸出級別,一共有8個級別,按照從低到高爲:all < trace < debug < info < warn < error < fatal < off,不指定level屬性時,默認爲error
    additivity屬性:用於指定是否同時輸出日誌到父級的Appender中,不指定additivity屬性時,默認爲true
    AppenderRef子節點:通過ref屬性用於指定日誌輸出到哪個Appender中,level屬性用於指定其日誌輸出級別,如果自定義日誌器Logger的level=trace,而其AppenderRef子節點的level=info,那麼該AppenderRef子節點引用的Appender只會輸出info級別及其以上的日誌信息,而不會輸出trace級別及其以上的日誌信息

 

六、Spring整合 Slf4j與Log4j2

1、在pom.xml文件中引入Slf4j和Log4j2的相關依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.log4j2</groupId>
    <artifactId>Log4j2Project</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <log4j.version>2.11.1</log4j.version>
    </properties>

    <dependencies>

        <!-- slf4j的相關依賴包 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>

        <!-- 橋接:告訴Slf4j使用Log4j2 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <!-- log4j2的相關依賴包 -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <!-- log4j2異步輸出的依賴包 -->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.4.2</version>
        </dependency>

    </dependencies>

</project>

 

2、在src/main/resources目錄下,創建一個名爲log4j2.xml的配置文件 ,其配置如下所示 (注意:配置文件的名稱最好爲log4j2.xml,因爲log4j2默認會去找一個名爲log4j2.xml的配置文件)

<?xml version="1.0" encoding="UTF-8"?>
<!--日誌級別以及優先級排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--status="WARN": 用於設置log4j2自身內部日誌的信息輸出級別,默認是OFF-->
<!--monitorInterval="1800": 間隔秒數,自動檢測配置文件的變更和重新配置本身-->
<configuration status="WARN" monitorInterval="1800">

    <Properties>
        <!--自定義一些常量,之後使用${變量名}引用-->
        <Property name="logFilePath">D:/logs</Property>
        <Property name="logFileName">myLog</Property>
    </Properties>

    <!--Appenders: 定義輸出內容,輸出格式,輸出方式,日誌保存策略等,常用其下三種標籤[console,File,RollingRandomAccessFile]-->
    <Appenders>
        <!--Console: 控制檯輸出的配置-->
        <console name="Console" target="SYSTEM_OUT" follow="true">
            <!--PatternLayout: 用於定義輸出日誌的格式-->
            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36}.%M() line:%L - %msg%xEx%n"/>
        </console>

        <!--File: 同步輸出日誌到本地文件-->
        <!--append="false": 根據其下日誌策略,每次清空文件重新輸入日誌,可用於測試-->
        <File name="File" fileName="${logFilePath}/${logFileName}.log" append="false">
            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36}.%M() line:%L - %msg%xEx%n"/>
        </File>

        <RollingRandomAccessFile name="RollingRandomAccessFile" fileName="${logFilePath}/logs/info.log"
                     filePattern="${logFilePath}/logs/$${date:yyyy-MM}/info-%d{yyyy-MM-dd HH}-%i.log" append="false">

            <!--  ACCEPT(接受)、DENY(拒絕)、NEUTRAL(中立) -->
            <!--  onMatch >= level  onMatch指的是日誌級別大於等於level時的操作 -->
            <!--  onMismatch < level onMismatch表示日誌級別小於level時的操作 -->
            <!--  通過添加兩組 ThresholdFilter 可以達到一個級別的log 對應一個文件的目的-->
            <Filters>
                <!-- 這裏設置只接收info級別的信息 -->
                <!--level="warn": 日誌級別,onMatch="DENY": 級別在info之上則拒絕,onMismatch="NEUTRAL": 級別在info之下則中立,即不作任何操作-->
                <ThresholdFilter level="warn" onMatch="DENY" onMismatch="NEUTRAL"/>
                <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY"/>
            </Filters>

            <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%t] [%class{36}.%M() line:%L] - %msg%xEx%n"/>

            <!-- Policies: 日誌滾動策略-->
            <Policies>
                <!--
                     TimeBasedTriggeringPolicy: 時間滾動策略,默認0點小時產生新的文件,interval="6": 自定義文件滾動時間間隔,
                     每隔6小時產生新文件, modulate="true": 產生文件是否以0點偏移時間,即6點、12點、18點、0點
                 -->
                <TimeBasedTriggeringPolicy interval="6" modulate="true"/>
                <!-- SizeBasedTriggeringPolicy :文件大小滾動策略-->
                <SizeBasedTriggeringPolicy size="60MB"/>
            </Policies>
            <!-- DefaultRolloverStrategy屬性如不設置,則默認爲最多同一文件夾下7個文件,這裏設置了10 -->
            <DefaultRolloverStrategy max="10"/>
        </RollingRandomAccessFile>

    </Appenders>

    <!--然後定義Logger,只有定義了Logger並引入的Appender,Appender纔會生效-->
    <Loggers>
        <!-- 過濾掉spring和mybatis的一些無用的DEBUG信息 -->
        <!-- Logger節點用來單獨指定日誌的形式,name爲包路徑,比如要爲org.springframework包下所有日誌指定爲error級別 -->
        <!-- 由於additivity屬性缺省,則默認爲true,其error級別以上(包括error級別)的日誌信息都會在頂級Root的Appender中被輸出 -->
        <Logger name="org.springframework" level="error"></Logger>
        <Logger name="org.mybatis" level="error"></Logger>

        <!-- Root節點用來指定項目的根日誌,如果沒有單獨指定Logger,那麼就會默認使用該Root日誌輸出 -->
        <Root level="warn">
            <appender-ref ref="Console"/>
            <appender-ref ref="File"/>
            <appender-ref ref="RollingRandomAccessFile"/>
        </Root>

        <!-- AsyncLogger: 異步日誌,LOG4J有三種日誌模式,全異步日誌,混合模式,同步日誌,性能從高到底,線程越多效率越高,也可以避免日誌卡死線程情況發生 -->
        <!-- additivity="false": additivity設置事件是否在父級logger 和 頂級Root的Appender中輸出,爲了避免重複輸出,可以在Logger標籤下設置additivity爲"false" -->
        <!-- includeLocation="true": 顯示文件行數,方法名等信息,對性能會有影響,能不用的情況下最好不用 -->
        <AsyncLogger name="com.log4j2" level="all" includeLocation="true" additivity="false">
            <appender-ref ref="RollingRandomAccessFile"/>
        </AsyncLogger>
    </Loggers>
</configuration>

 

3、在com.log4j2包路徑下創建一個名爲Log4j2Test類,注意:這裏導入的包都是slf4j的包而不是具體某個日誌框架中的包

package com.log4j2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Log4j2Test {

    private static final Logger logger = LoggerFactory.getLogger(Log4j2.class);

    public static void main(String[] args) {

        for (int i = 0; i < 10; i++) {

            logger.trace("trace level "+i);
            logger.debug("debug level "+i);
            logger.info("info level "+i);
            logger.warn("warn level "+i);
            logger.error("error level "+i);
           
        }
    }
}

 

4、其運行結果如下所示

 

 

 

擴展補充:

七、配置log4j2.xml在控制檯打印Mybatis執行的SQL語句

1、自定義一個Logger,設置其name屬性爲項目持久層接口 (與Mybatis配置Sql文件對應接口) 的package (包路徑),再設置其level爲"debug",最後設置其日誌在控制檯輸出,配置如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!--日誌級別以及優先級排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--status="WARN": 用於設置log4j2自身內部日誌的信息輸出級別,默認是OFF-->
<!--monitorInterval="1800": 間隔秒數,自動檢測配置文件的變更和重新配置本身-->
<configuration status="WARN" monitorInterval="1800">

    <!--Appenders: 定義輸出內容,輸出格式,輸出方式,日誌保存策略等,常用其下三種標籤[console,File,RollingRandomAccessFile]-->
    <Appenders>
        <!--Console: 控制檯輸出的配置-->
        <console name="Console" target="SYSTEM_OUT" follow="true">
            <!--PatternLayout: 用於定義輸出日誌的格式-->
            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36}.%M() line:%L - %msg%xEx%n"/>
        </console>
    </Appenders>

    <!--然後定義Logger,只有定義了Logger並引入的Appender,Appender纔會生效-->
    <Loggers>

        <!-- 將與數據庫交互的dao/mapper接口的包名填寫到Logger的name屬性中,並設置Appender爲控制檯輸出即可 -->
         <!-- additivity="false": additivity設置事件是否在父級logger 和 頂級Root的Appender中輸出,爲了避免重複輸出,可以在Logger標籤下設置additivity爲"false" -->
        <Logger name="com.log4j2.mapper" level="debug" additivity="false">
            <appender-ref ref="Console"/>
        </Logger>

        <!-- Root節點用來指定項目的根日誌,如果沒有單獨指定Logger,那麼就會默認使用該Root日誌輸出 -->
        <Root level="warn">
            <appender-ref ref="Console"/>
        </Root>
    </Loggers>
</configuration>

 

2、這裏的level爲debug,只會打印Mybatis執行的sql語句、sql參數和結果條數,其運行結果如下所示:

2019-08-20 10:56:06.775 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug() line:159 - ==>  Preparing: select id, name, sex, age, birthday from user where id=? 
2019-08-20 10:56:06.865 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug() line:159 - ==> Parameters: 1(Integer)
2019-08-20 10:56:06.877 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug() line:159 - <==      Total: 1

 

3、如果把level設置爲trace,則會打印Mybatis執行的sql語句、sql參數、執行的結果和結果條數,其運行結果如下所示:

2019-08-20 10:58:55.825 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug() line:159 - ==>  Preparing: select id, name, sex, age, birthday from user where id=? 
2019-08-20 10:58:55.851 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug() line:159 - ==> Parameters: 1(Integer)
2019-08-20 10:58:55.860 TRACE org.apache.ibatis.logging.jdbc.BaseJdbcLogger.trace() line:165 - <==    Columns: id, name, sex, age, birthday
2019-08-20 10:58:55.861 TRACE org.apache.ibatis.logging.jdbc.BaseJdbcLogger.trace() line:165 - <==        Row: 1, 曾華, 男, 42, 1977-09-01
2019-08-20 10:58:55.864 DEBUG org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug() line:159 - <==      Total: 1

 

八、配置log4j2.xml把日誌寫入到數據庫中

1、創建日誌記錄表error_log

DROP TABLE IF EXISTS `error_log`;
CREATE TABLE `error_log` (
  `log_id` int(20) NOT NULL AUTO_INCREMENT,
  `class` varchar(200) DEFAULT NULL COMMENT '類的全路徑名',
  `method` varchar(100) DEFAULT NULL COMMENT '方法名',
  `line` int(20) DEFAULT NULL COMMENT '所在行號',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  `log_level` varchar(50) DEFAULT NULL COMMENT '日誌級別',
  `msg` varchar(4000) DEFAULT NULL COMMENT '日誌信息',
  PRIMARY KEY (`log_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

2、在log4j2.xml中配置JDBC輸出源

<?xml version="1.0" encoding="UTF-8"?>
<!--日誌級別以及優先級排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--status="WARN": 用於設置log4j2自身內部日誌的信息輸出級別,默認是OFF-->
<!--monitorInterval="1800": 間隔秒數,自動檢測配置文件的變更和重新配置本身-->
<configuration status="WARN" monitorInterval="1800">

    <!--Appenders: 定義輸出內容,輸出格式,輸出方式,日誌保存策略等,常用其下三種標籤[console,File,RollingRandomAccessFile]-->
    <Appenders>
        <!--Console: 控制檯輸出的配置-->
        <console name="Console" target="SYSTEM_OUT" follow="true">
            <!--PatternLayout: 用於定義輸出日誌的格式-->
            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36}.%M() line:%L - %msg%xEx%n"/>
        </console>

        <!--寫入數據庫配置,在Logger中設置日誌級別爲error-->
        <JDBC name="databaseAppender" tableName="error_log">
            <ConnectionFactory class="com.log4j2.ConnectionFactoryConfig" method="getDataSourceConnection" />
            <Column name="class" pattern="%c" />
            <Column name="method" pattern="%M" />
            <Column name="line" pattern="%L" />
            <Column name="log_level" pattern="%p" />
            <Column name="msg" pattern="%msg"/>
            <Column name="create_time" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}"/>
        </JDBC>
    </Appenders>

    <!--然後定義Logger,只有定義了Logger並引入的Appender,Appender纔會生效-->
    <Loggers>

        <!-- 將與數據庫交互的dao/mapper接口的包名填寫到Logger的name屬性中,並設置Appender爲控制檯輸出即可 -->
        <!-- additivity="false": additivity設置事件是否在父級logger 和 頂級Root的Appender中輸出,爲了避免重複輸出,可以在Logger標籤下設置additivity爲"false" -->
        <Logger name="com.log4j2" level="trace" additivity="false">
            <!-- level="debug": 設置只打印debug級別以上的日誌信息 -->
            <appender-ref ref="Console" level="debug"/>
            <appender-ref ref="databaseAppender" level="error"/>
        </Logger>

        <!-- Root節點用來指定項目的根日誌,如果沒有單獨指定Logger,那麼就會默認使用該Root日誌輸出 -->
        <Root level="warn">
            <appender-ref ref="Console"/>
        </Root>
    </Loggers>
</configuration>

 

3、在src/main/resources目錄下,創建一個properties文件夾,並在其文件夾中創建一個jdbc.properties文件,用於配置數據庫信息

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3316/log4j2?rewriteBatchedStatements=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false&&useSSL=false
jdbc.username=root
jdbc.password=123456

 

4、在pom.xml文件中引入Druid的依賴

<!-- Druid連接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.10</version>
</dependency>

 

5、創建數據庫連接類ConnectionFactoryConfig,使用的是druid數據源

package com.log4j2;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class ConnectionFactoryConfig {

    private static String driverClassName = null;
    private static String dbUrl = null;
    private static String username = null;
    private static String password = null;
    private DruidDataSource dataSource = null;
    private static ConnectionFactoryConfig instance = null;

    /**
     * 獲取數據庫連接對象
     * @return
     * @throws SQLException
     */
    public static Connection getDataSourceConnection() throws SQLException {
        if (instance == null) {
            instance = new ConnectionFactoryConfig();
        }
        return instance.getConnection();
    }

    
    /**
     * 取消初始化
     */
    public void uninitialize() {
        try {
            if (dataSource != null && !dataSource.isClosed()) {
                dataSource.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    

    /**
     * 獲取數據庫連接
     * @return
     * @throws SQLException
     */
    private Connection getConnection() throws SQLException {
        loadPropertiesFile();

        try {
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(getProperties());
        } catch (Exception e) {
            e.printStackTrace();
            uninitialize();
        }
        return dataSource.getConnection();
    }


    /**
     * 創建Properties 實例
     * @return Properties 實體類
     */
    private Properties getProperties() {
        Properties properties = new Properties();
        properties.put("driverClassName", driverClassName);
        properties.put("url", dbUrl);
        properties.put("username", username);
        properties.put("password", password);
        return properties;
    }


    /**
     * 加載資源文件
     */
    private void loadPropertiesFile() {
        InputStream resourceAsStream = ConnectionFactoryConfig.class.getClassLoader().getResourceAsStream("properties/jdbc.properties");
        Properties props = new Properties();
        try {
            props.load(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

        driverClassName = props.getProperty("jdbc.driver");
        dbUrl = props.getProperty("jdbc.url");
        username = props.getProperty("jdbc.username");
        password = props.getProperty("jdbc.password");
    }
    
}

 

6、在com.log4j2包路徑下創建一個名爲JdbcLog4j2Test類,注意:這裏導入的包都是slf4j的包而不是具體某個日誌框架中的包

package com.easyexcel;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class JdbcLog4j2Test {

    private static final Logger logger = LoggerFactory.getLogger(JdbcLog4j2Test.class);

    public static void main(String[] args) {

            logger.trace("trace level");
            logger.debug("debug level");
            logger.info("info level");
            logger.warn("warn level");
            logger.error("error level");
    }

}

 

7、其運行結果如下所示

 

 

 

九、SpringBoot整合 Slf4j與Log4j2

1、在pom.xml文件中引入Slf4j和Log4j2的相關依賴

        <!-- springboot起步依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>

            <!-- 排除自帶的Logback日誌工具依賴,爲了項目使用Log4j2日誌打印工具 -->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--
             1、log4j2的依賴包
             2、spring-boot-starter-log4j2 中自動依賴了 slf4j-api 和 log4j-slf4j-impl
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

        <!-- log4j2異步輸出的依賴包 -->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>3.4.2</version>
        </dependency>

 

2、在src/main/resources目錄下,創建一個名爲log4j2.xml的配置文件 ,其配置如下所示

<?xml version="1.0" encoding="UTF-8"?>
<!--日誌級別以及優先級排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<!--status="WARN": 用於設置log4j2自身內部日誌的信息輸出級別,默認是OFF-->
<!--monitorInterval="1800": 間隔秒數,自動檢測配置文件的變更和重新配置本身-->
<configuration status="WARN" monitorInterval="1800">


    <!--Appenders: 定義輸出內容,輸出格式,輸出方式,日誌保存策略等,常用其下三種標籤[console,File,RollingRandomAccessFile]-->
    <Appenders>
        <!--Console: 控制檯輸出的配置-->
        <console name="Console" target="SYSTEM_OUT" follow="true">
            <!--PatternLayout: 用於定義輸出日誌的格式-->
            <PatternLayout charset="UTF-8" pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %class{36}.%M() line:%L - %msg%xEx%n"/>
        </console>

    </Appenders>

    <!--然後定義Logger,只有定義了Logger並引入的Appender,Appender纔會生效-->
    <Loggers>

        <!-- Root節點用來指定項目的根日誌,如果沒有單獨指定Logger,那麼就會默認使用該Root日誌輸出 -->
        <Root level="info">
            <appender-ref ref="Console"/>
        </Root>

    </Loggers>
</configuration>

 

3、在com.log4j2包路徑下創建一個名爲Log4j2Test類,注意:這裏導入的包都是slf4j的包而不是具體某個日誌框架中的包

package com.log4j2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Log4j2 {

   private static final Logger logger = LoggerFactory.getLogger(Log4j2.class);

    public static void main(String[] args) {

        logger.info("INFO:Log4j2 --- info level");
        logger.warn("WARN:Log4j2 --- warn level");
        logger.error("ERROR:Log4j2 --- error level");
    }
}

 

4、其運行結果如下所示

2019-09-26 09:20:33.679 INFO  com.log4j2.Log4j2.main() line:12 - INFO:Log4j2 --- info level
2019-09-26 09:20:33.682 WARN  com.log4j2.Log4j2.main() line:13 - WARN:Log4j2 --- warn level
2019-09-26 09:20:33.682 ERROR com.log4j2.Log4j2.main() line:14 - ERROR:Log4j2 --- error level

 

 

 

                      如果有遇到不懂或者有問題時,可以掃描下方二維碼,歡迎進羣交流與分享,希望能夠跟大家交流學習!

                                                                          

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章