日誌框架logback

原文鏈接:https://juejin.im/post/5b51f85c5188251af91a7525

簡介

  • logbacklog4j是一個人寫的
  • springboot默認使用的日誌框架是logback
  • 三個模塊組成
    • logback-core
    • logback-classic
    • logback-access
  • 其他的關於性能,關於內存佔用,關於測試,關於文檔詳見源碼及官網說明

logback-core 是其它模塊的基礎設施,其它模塊基於它構建,顯然,logback-core 提供了一些關鍵的通用機制。logback-classic 的地位和作用等同於 Log4J,它也被認爲是 Log4J 的一個改進版,並且它實現了簡單日誌門面 SLF4J;而 logback-access 主要作爲一個與 Servlet 容器交互的模塊,比如說tomcat或者 jetty,提供一些與 HTTP 訪問相關的功能。

配置文件詳解

這部分主要來學習下logback配置文件的一些配置項。

configuration

先來看這張圖,這個結構就是整個logback.xml配置文件的結構。

 

 

對應來看下配置文件:

 

<configuration scan="true" scanPeriod="60 seconds" debug="false">  
    <property name="glmapper-name" value="glmapper-demo" /> 
    <contextName>${glmapper-name}</contextName> 
    
    
    <appender>
        //xxxx
    </appender>   
    
    <logger>
        //xxxx
    </logger>
    
    <root>             
       //xxxx
    </root>  
</configuration>  
複製代碼

ps:想使用spring擴展profile支持,要以logback-spring.xml命名,其他如property需要改爲springProperty

  • scan:當此屬性設置爲true時,配置文件如果發生改變,將會被重新加載,默認值爲true。
  • scanPeriod:設置監測配置文件是否有修改的時間間隔,如果沒有給出時間單位,默認單位是毫秒。當scan爲true時,此屬性生效。默認的時間間隔爲1分鐘。
  • debug:當此屬性設置爲true時,將打印出logback內部日誌信息,實時查看logback運行狀態。默認值爲false。

contextName

每個logger都關聯到logger上下文,默認上下文名稱爲“default”。但可以使用contextName標籤設置成其他名字,用於區分不同應用程序的記錄

property

用來定義變量值的標籤,property標籤有兩個屬性,namevalue;其中name的值是變量的名稱,value的值時變量定義的值。通過property定義的值會被插入到logger上下文中。定義變量後,可以使“${name}”來使用變量。如上面的xml所示。

logger

用來設置某一個包或者具體的某一個類的日誌打印級別以及指定appender

root

根logger,也是一種logger,且只有一個level屬性

appender

負責寫日誌的組件,下面會細說

filter

filter其實是appender裏面的子元素。它作爲過濾器存在,執行一個過濾器會有返回DENY,NEUTRAL,ACCEPT三個枚舉值中的一個。

  • DENY:日誌將立即被拋棄不再經過其他過濾器
  • NEUTRAL:有序列表裏的下個過濾器過接着處理日誌
  • ACCEPT:日誌會被立即處理,不再經過剩餘過濾器

案例分析

首先來配置一個非常簡單的文件。這裏申請下,我使用的是 logback-spring.xml。和 logback.xmlproperties上有略微差別。其他都一樣。

工程:springboot+web

先來看下項目目錄

 

 

 

properties中就是指定了日誌的打印級別和日誌的輸出位置:

#設置應用的日誌級別
logging.level.com.glmapper.spring.boot=INFO
#路徑
logging.path=./logs
複製代碼

通過控制檯輸出的log

logback-spring.xml的配置如下:

<configuration>
    <!-- 默認的控制檯日誌輸出,一般生產環境都是後臺啓動,這個沒太大作用 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%d{HH:mm:ss.SSS} %-5level %logger{80} - %msg%n</Pattern>
        </encoder>
    </appender>
    
    <root level="info">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>
複製代碼

打印日誌的controller

private static final Logger LOGGER =
LoggerFactory.getLogger(HelloController.class);
@Autowired
private TestLogService testLogService;

@GetMapping("/hello")
public String hello(){
    LOGGER.info("GLMAPPER-SERVICE:info");
    LOGGER.error("GLMAPPER-SERVICE:error");
    testLogService.printLogToSpecialPackage();
    return "hello spring boot";
}
複製代碼

驗證結果:

01:50:39.633 INFO  com.glmapper.spring.boot.controller.HelloController
- GLMAPPER-SERVICE:info
01:50:39.633 ERROR com.glmapper.spring.boot.controller.HelloController
- GLMAPPER-SERVICE:error
複製代碼

上面的就是通過控制檯打印出來的,這個時候因爲我們沒有指定日誌文件的輸出,因爲不會在工程目錄下生產logs文件夾。

控制檯不打印,直接輸出到日誌文件

先來看下配置文件:

<configuration>
    <!-- 屬性文件:在properties文件中找到對應的配置項 -->
    <springProperty scope="context" name="logging.path"  source="logging.path"/>
    <springProperty scope="context" name="logging.level" source="logging.level.com.glmapper.spring.boot"/>
    <!-- 默認的控制檯日誌輸出,一般生產環境都是後臺啓動,這個沒太大作用 -->
    <appender name="STDOUT"
        class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <Pattern>%d{HH:mm:ss.SSS} %-5level %logger{80} - %msg%n</Pattern>
        </encoder>
    </appender>
    
    <appender name="GLMAPPER-LOGGERONE"
    class="ch.qos.logback.core.rolling.RollingFileAppender">
        <append>true</append>
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>${logging.level}</level>
        </filter>
        <file>
            ${logging.path}/glmapper-spring-boot/glmapper-loggerone.log
        </file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-loggerone.log.%d{yyyy-MM-dd}</FileNamePattern>
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    
    <root level="info">
        <appender-ref ref="GLMAPPER-LOGGERONE"/>
    </root>
</configuration>
複製代碼

這裏我們appender-ref指定的appenderGLMAPPER-LOGGERONE,因爲之前沒有名字爲GLMAPPER-LOGGERONEappender,所以要增加一個nameGLMAPPER-LOGGERONEappender

注意上面這個配置,我們是直接接將rootappender-ref直接指定到我們的GLMAPPER-LOGGERONE這個appender的。所以控制檯中將只會打印出bannar之後就啥也不打印了,所有的啓動信息都會被打印在日誌文件glmapper-loggerone.log中。

 

 

 

但是實際上我們不希望我的業務日誌中會包括這些啓動信息。所以這個時候我們就需要通過logger標籤來搞事情了。將上面的配置文件進行簡單修改:

<logger name="com.glmapper.spring.boot.controller" level="${logging.level}"
        additivity="false">
    <appender-ref ref="GLMAPPER-LOGGERONE" />
</logger>

<root level="${logging.level}">
    <appender-ref ref="STDOUT"/>
</root>
複製代碼

root指向控制檯輸出;logger負責打印包com.glmapper.spring.boot.controller下的日誌。

驗證結果

還是通過我們的測試controller來打印日誌爲例,但是這裏不會在控制檯出現日誌信息了。期望的日誌文件在./logs/glmapper-spring-boot/glmapper-loggerone.log

 

 

 

logger和appender的關係

上面兩種是一個基本的配置方式,通過上面兩個案例,我們先來了解下logger/appender/root之間的關係,然後再詳細的說下loggerappender的配置細節。

在最前面介紹中提到,root是根logger,所以他兩是一回事;只不過root中不能有nameadditivity屬性,是有一個level

appender是一個日誌打印的組件,這裏組件裏面定義了打印過濾的條件、打印輸出方式、滾動策略、編碼方式、打印格式等等。但是它僅僅是一個打印組件,如果我們不使用一個logger或者rootappender-ref指定某個具體的appender時,它就沒有什麼意義。

因此appender讓我們的應用知道怎麼打、打印到哪裏、打印成什麼樣;而logger則是告訴應用哪些可以這麼打。例如某個類下的日誌可以使用這個appender打印或者某個包下的日誌可以這麼打印。

appender 配置詳解

這裏以上面案例中的名爲GLMAPPER-LOGGERONEappender說明:

<appender name="GLMAPPER-LOGGERONE"
    class="ch.qos.logback.core.rolling.RollingFileAppender">
    <append>true</append>
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>${logging.level}</level>
    </filter>
    <file>
        ${logging.path}/glmapper-spring-boot/glmapper-loggerone.log
    </file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-loggerone.log.%d{yyyy-MM-dd}</FileNamePattern>
        <MaxHistory>30</MaxHistory>
    </rollingPolicy>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        <charset>UTF-8</charset>
    </encoder>
</appender>
複製代碼

appender 有兩個屬性 nameclass;name指定appender名稱,class指定appender的全限定名。上面聲明的是名爲GLMAPPER-LOGGERONEclassch.qos.logback.core.rolling.RollingFileAppender的一個appender

appender 的種類

  • ConsoleAppender:把日誌添加到控制檯
  • FileAppender:把日誌添加到文件
  • RollingFileAppender:滾動記錄文件,先將日誌記錄到指定文件,當符合某個條件時,將日誌記錄到其他文件。它是FileAppender的子類

append 子標籤

<append>true</append>
複製代碼

如果是 true,日誌被追加到文件結尾,如果是false,清空現存文件,默認是true

filter 子標籤

在簡介中提到了filter;作用就是上面說的。可以爲appender 添加一個或多個過濾器,可以用任意條件對日誌進行過濾。appender 有多個過濾器時,按照配置順序執行。

ThresholdFilter

臨界值過濾器,過濾掉低於指定臨界值的日誌。當日志級別等於或高於臨界值時,過濾器返回NEUTRAL;當日志級別低於臨界值時,日誌會被拒絕。

<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
    <level>INFO</level>
</filter>
複製代碼

LevelFilter

級別過濾器,根據日誌級別進行過濾。如果日誌級別等於配置級別,過濾器會根據onMath(用於配置符合過濾條件的操作) 和 onMismatch(用於配置不符合過濾條件的操作)接收或拒絕日誌。

<filter class="ch.qos.logback.classic.filter.LevelFilter">   
  <level>INFO</level>   
  <onMatch>ACCEPT</onMatch>   
  <onMismatch>DENY</onMismatch>   
</filter> 
複製代碼

關於NEUTRALACCEPTDENY 見上文簡介中關於filter的介紹。

file 子標籤

file 標籤用於指定被寫入的文件名,可以是相對目錄,也可以是絕對目錄,如果上級目錄不存在會自動創建,沒有默認值。

<file>
    ${logging.path}/glmapper-spring-boot/glmapper-loggerone.log
</file>
複製代碼

這個表示當前appender將會將日誌寫入到${logging.path}/glmapper-spring-boot/glmapper-loggerone.log這個目錄下。

rollingPolicy 子標籤

這個子標籤用來描述滾動策略的。這個只有appenderclassRollingFileAppender時才需要配置。這個也會涉及文件的移動和重命名(a.log->a.log.2018.07.22)。

TimeBasedRollingPolicy

最常用的滾動策略,它根據時間來制定滾動策略,既負責滾動也負責出發滾動。這個下面又包括了兩個屬性:

  • FileNamePattern
  • maxHistory
<rollingPolicy 
    class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <!--日誌文件輸出的文件名:按天回滾 daily -->
    <FileNamePattern>
        ${logging.path}/glmapper-spring-boot/glmapper-loggerone.log.%d{yyyy-MM-dd}
    </FileNamePattern>
    <!--日誌文件保留天數-->
    <MaxHistory>30</MaxHistory>
</rollingPolicy>
複製代碼

上面的這段配置表明每天生成一個日誌文件,保存30天的日誌文件

FixedWindowRollingPolicy

根據固定窗口算法重命名文件的滾動策略。

encoder 子標籤

對記錄事件進行格式化。它幹了兩件事:

  • 把日誌信息轉換成字節數組
  • 把字節數組寫入到輸出流
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}
    - %msg%n</pattern>
    <charset>UTF-8</charset>
</encoder>
複製代碼

目前encoder只有PatternLayoutEncoder一種類型。

定義一個只打印error級別日誌的appcener

 <!-- 錯誤日誌 appender : 按照每天生成日誌文件 -->
<appender name="ERROR-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <append>true</append>
    <!-- 過濾器,只記錄 error 級別的日誌 -->
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>error</level>
    </filter>
    <!-- 日誌名稱 -->
    <file>${logging.path}/glmapper-spring-boot/glmapper-error.log</file>
    <!-- 每天生成一個日誌文件,保存30天的日誌文件 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!--日誌文件輸出的文件名:按天回滾 daily -->
        <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-error.log.%d{yyyy-MM-dd}</FileNamePattern>
        <!--日誌文件保留天數-->
        <MaxHistory>30</MaxHistory>
    </rollingPolicy>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日誌消息,%n是換行符-->
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        <!-- 編碼 -->
        <charset>UTF-8</charset>
    </encoder>
</appender>
複製代碼

定義一個輸出到控制檯的appender

<!-- 默認的控制檯日誌輸出,一般生產環境都是後臺啓動,這個沒太大作用 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <Pattern>%d{HH:mm:ss.SSS} %-5level %logger{80} - %msg%n</Pattern>
    </encoder>
</appender>
複製代碼

logger 配置詳解

<logger name="com.glmapper.spring.boot.controller"
        level="${logging.level}" additivity="false">
    <appender-ref ref="GLMAPPER-LOGGERONE" />
</logger>
複製代碼

上面的這個配置文件描述的是:com.glmapper.spring.boot.controller這個包下的${logging.level}級別的日誌將會使用GLMAPPER-LOGGERONE來打印。logger有三個屬性和一個子標籤:

  • name:用來指定受此logger約束的某一個包或者具體的某一個類。
  • level:用來設置打印級別(TRACE, DEBUG, INFO, WARN, ERROR, ALLOFF),還有一個值INHERITED或者同義詞NULL,代表強制執行上級的級別。如果沒有設置此屬性,那麼當前logger將會繼承上級的級別。
  • addtivity:用來描述是否向上級logger傳遞打印信息。默認是true

appender-ref則是用來指定具體appender的。

不同日誌隔離打印案例

在前面的例子中我們有三種appender,一個是指定包約束的,一個是控制error級別的,一個是控制檯的。然後這小節我們就來實現下不同日誌打印到不同的log文件中。

根據包進行日誌文件隔離

這個例子裏我們將com.glmapper.spring.boot.controller中的日誌輸出到glmapper-controller.log;將com.glmapper.spring.boot.service中的日誌輸出到glmapper-service.log

<!--打印日誌到glmapper-service.log的appender-->
<appender name="GLMAPPER-SERVICE"
          class="ch.qos.logback.core.rolling.RollingFileAppender">
    <append>true</append>
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>${logging.level}</level>
    </filter>
    <file>
        ${logging.path}/glmapper-spring-boot/glmapper-service.log
    </file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-service.log.%d{yyyy-MM-dd}</FileNamePattern>
        <MaxHistory>30</MaxHistory>
    </rollingPolicy>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        <charset>UTF-8</charset>
    </encoder>
</appender>

<!--打印日誌到glmapper-controller.log的appender-->
<appender name="GLMAPPER-CONTROLLER"
          class="ch.qos.logback.core.rolling.RollingFileAppender">
    <append>true</append>
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>${logging.level}</level>
    </filter>
    <file>
        ${logging.path}/glmapper-spring-boot/glmapper-controller.log
    </file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-controller.log.%d{yyyy-MM-dd}</FileNamePattern>
        <MaxHistory>30</MaxHistory>
    </rollingPolicy>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        <charset>UTF-8</charset>
    </encoder>
</appender>

<!--此logger約束將.controller包下的日誌輸出到GLMAPPER-CONTROLLER,錯誤日誌輸出到GERROR-APPENDE;GERROR-APPENDE見上面-->
<logger name="com.glmapper.spring.boot.controller" level="${logging.level}" additivity="false">
    <appender-ref ref="GLMAPPER-CONTROLLER" />
    <appender-ref ref="GERROR-APPENDER" />
</logger>

<!--此logger約束將.service包下的日誌輸出到GLMAPPER-SERVICE,錯誤日誌輸出到GERROR-APPENDE;GERROR-APPENDE見上面-->
<logger name="com.glmapper.spring.boot.service" level="${logging.level}" additivity="false">
    <appender-ref ref="GLMAPPER-SERVICE" />
    <appender-ref ref="GERROR-APPENDER" />
</logger>
複製代碼

來看運行結果

1、glmaper-controller

 

 

 

2、glmapper-service

 

 

 

3、glmapper-error

 

 

 

滿足我們的預期,但是這裏有個小問題。在info日誌裏出現了error,當然這是正常的。假如我們不想在info裏面出現error怎麼辦呢?很簡單,我們以APPENDER-SERVICE爲例,將filter過濾器進行修改:

將下面的:

<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
    <level>${logging.level}</level>
</filter>
複製代碼

修改爲:

<filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>ERROR</level>
    <!-- 如果命中就禁止這條日誌 -->
    <onMatch>DENY</onMatch>  
    <!-- 如果沒有命中就使用這條規則 -->
    <onMismatch>ACCEPT</onMismatch>  
</filter>
複製代碼

這裏同時要注意的是,在loggerlevel需要設置爲info級別。

根據類進行日誌文件隔離

這個其實也是和上面那個差不過,只不過粒度更細一點,一般情況下比如說我們有個定時任務類需要單獨來記錄其日誌信息,這樣我們就可以考慮使用基於類維度來約束打印。

<!--特殊功能單獨appender 例如調度類的日誌-->
<appender name="SCHEDULERTASKLOCK-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <append>true</append>
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>${logging.level}</level>
    </filter>
    <file>${logging.path}/glmapper-spring-boot/scheduler-task-lock.log</file>
    <!-- 每天生成一個日誌文件,保存30天的日誌文件 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!--日誌文件輸出的文件名:按天回滾 daily -->
        <FileNamePattern>${logging.path}/glmapper-spring-boot/scheduler-task-lock.log.%d{yyyy-MM-dd}</FileNamePattern>
        <!--日誌文件保留天數-->
        <MaxHistory>30</MaxHistory>
    </rollingPolicy>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日誌消息,%n是換行符-->
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        <!-- 編碼 -->
        <charset>UTF-8</charset>
    </encoder>
</appender>

<!--這裏指定到了具體的某一個類-->
<logger name="com.glmapper.spring.boot.task.TestLogTask" level="${logging.level}" additivity="true">
        <appender-ref ref="SCHEDULERTASKLOCK-APPENDER" />
        <appender-ref ref="ERROR-APPENDER" />
    </logger>
複製代碼

最終TestLogTask中的日誌將會被打印到這個自己獨立的log文件中。如下所示:

 

 

 

根據自定義 logger 的 name 進行日誌文件隔離

loggername除了類、包等約束之外,當然還可以這樣來玩。。。

在進行案例之前,這裏先把前面案例中logger聲明的代碼貼一下,以作對比,以TestLogTask類中的日誌爲例:

 private static final Logger LOGGER =
 LoggerFactory.getLogger(TestLogTask.class);
複製代碼

getLogger中我們是將當前對象的class作爲參數的,這個是爲了打印時獲取其全限定名的(見下面3-)。

1-2018-07-21 11:15:42.003 [pool-1-thread-1] 
2-INFO  
3-com.glmapper.spring.boot.task.TestLogTask -
4-com.glmapper.spring.boot.task:info
複製代碼

業務類定義

我們同樣是service包下定義一個類TestLogNameServiceImpl

package com.glmapper.spring.boot.service;

@Service("testLogNameService")
public class TestLogNameServiceImpl implements TestLogNameService {

    private static final Logger LOGGER =
    LoggerFactory.getLogger("GLMAPPER-TEST-LOG");

    @Override
    public void print() {
        LOGGER.info("GLMAPPER-TEST-LOG:this is special logger-----info");
        LOGGER.error("GLMAPPER-TEST-LOG:this is special logger-------error");
    }
}
複製代碼

appender和logger配置

<appender name="ROOT-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <append>true</append>
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>${logging.level}</level>
    </filter>
    <file>${logging.path}/glmapper-spring-boot/glmapper-test.log</file>
    <!-- 每天生成一個日誌文件,保存30天的日誌文件 -->
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <!--日誌文件輸出的文件名:按天回滾 daily -->
        <FileNamePattern>${logging.path}/glmapper-spring-boot/glmapper-test.log.%d{yyyy-MM-dd}
        </FileNamePattern>
        <!--日誌文件保留天數-->
        <MaxHistory>30</MaxHistory>
    </rollingPolicy>
    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
        <!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度%msg:日誌消息,%n是換行符-->
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        <!-- 編碼 -->
        <charset>UTF-8</charset>
    </encoder>
</appender>

<!--這裏的name和業務類中的getLogger中的字符串是一樣的-->
<logger name="GLMAPPER-TEST-LOG" level="${logging.level}" additivity="true">
        <appender-ref ref="ROOT-APPENDER" />
        <appender-ref ref="ERROR-APPENDER" />
    </logger>
複製代碼

我們這個預期的是TestLogNameServiceImpl中的日誌不打印到glmapper-service.log中,而是打印到glmapper-test.log中。

1、glmapper-test.log

 

 

 

2、glmapper-service.log

 

 

 

滿足我們的預期。

如何使用logback打印mybatis的sql語句

這個還是比較坑的。爲什麼。看下這個:

<settings>
    <setting name="logImpl" value="slf4j" />
</settings>
複製代碼

mybatis-configration.xml中,我們通過這樣一個配置項來關聯到具體的日誌組件。但是logImpl的實現中是沒有logback的。那麼怎麼辦呢?這裏只能通過slf4j的方式橋接到logback

然後在我們的logback-spring.xml中進行如下配置:

 <!-- 將sql語句輸出到具體的日誌文件中 -->
<logger name="com.alipay.sofa.cloudplatform.common.dao" level="${logging.sql.level}" additivity="false">
    <appender-ref ref="SQL-APPENDER"/>
</logger>
複製代碼

這裏有幾個點需要注意的。首先是${logging.sql.level}這個必須是debug,這個是由mybatis本身實現決定的。而這裏的name設定的com.alipay.sofa.cloudplatform.common.dao值就是我們dao接口的包路徑。

網上看了一個比較典型的案例,這種方式只能輸出到控制檯,並不能將文件輸出到日誌文件;它是根據內部的一個實現機制偷了個懶。mybatis用logback日誌不顯示sql的解決辦法

總結

本篇博客主要是整理最近工作中的一些日誌配置積累,將每個細節進行總結一下,以作備忘。如果有時間的話會考慮看一個日誌框架的源碼。其實我覺得還是很有必要的,日誌組件畢竟是需要進行日誌文件落盤的,這個會涉及到許多的性能問題、緩衝區問題、隊列問題、當然還有一些鎖的問題、同步打印或者異步打印等問題。有興趣的小夥伴可以看看,然後分享給我們。


作者:glmapper
鏈接:https://juejin.im/post/5b51f85c5188251af91a7525
 

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