Spring Boot 第三彈,一文帶你瞭解日誌如何配置?

愛撒謊的男孩發表於2020-09-29

前言

日誌通常不會在需求階段作為一個功能單獨提出來,也不會在產品方案中看到它的細節。但是,這絲毫不影響它在任何一個系統中的重要的地位。

今天就來介紹一下Spring Boot中的日誌如何配置。

Spring Boot 版本

本文基於的Spring Boot的版本是2.3.4.RELEASE

日誌級別

幾種常見的日誌級別由低到高分為:TRACE < DEBUG < INFO < WARN < ERROR < FATAL

如何理解這個日誌級別呢?很簡單,如果專案中的日誌級別設定為INFO,那麼比它更低階別的日誌資訊就看不到了,即是TRACEDEBUG日誌將會不顯示。

日誌框架有哪些?

常見的日誌框架有log4jlogbacklog4j2

log4j這個日誌框架顯示是耳熟能詳了,在Spring開發中是經常使用,但是據說log4j官方已經不再更新了,而且在效能上比logbacklog4j2差了很多。

logback是由log4j創始人設計的另外一個開源日誌框架,logback相比之於log4j效能提升了10以上,初始化記憶體載入也更小了。作為的Spring Boot預設的日誌框架肯定是有著不小的優勢。

log4j2晚於logback推出,官網介紹效能比logback高,但誰知道是不是王婆賣瓜自賣自誇,坊間流傳,log4j2在很多思想理念上都是照抄logback,因此即便log4j2是Apache官方專案,Spring等許多框架專案沒有將它納入主流。此處完全是作者道聽途說,不必當真,題外話而已

日誌框架很多,究竟如何選擇能夠適應現在的專案開發,當然不是普通程式設計師考慮的,但是為了更高的追求,至少應該瞭解一下,哈哈。

Spring Boot 日誌框架

Spring Boot預設的日誌框架是logback,既然Spring Boot能夠將其納入的預設的日誌系統,肯定是有一定的考量的,因此實際開發過程中還是不要更換。

原則上需要使用logback,需要新增以下依賴,但是既然是預設的日誌框架,當然不用重新引入依賴了。

<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>

Spring Boot中預設的日誌級別是INFO,啟動專案日誌列印如下:

從上圖可以看出,輸出的日誌的預設元素如下:

  1. 時間日期:精確到毫秒
  2. 日誌級別:ERROR, WARN, INFO, DEBUG , TRACE
  3. 程式ID
  4. 分隔符:— 標識實際日誌的開始
  5. 執行緒名:方括號括起來(可能會截斷控制檯輸出)
  6. Logger名:通常使用原始碼的類名
  7. 日誌內容

程式碼中如何使用日誌?

在業務中肯定需要追溯日誌,那麼如何在自己的業務中輸出日誌呢?其實常用的有兩種方式,下面一一介紹。

第一種其實也是很早之前常用的一種方式,只需要在程式碼新增如下:

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

這種方式顯然比較雞肋,如果每個類中都新增一下豈不是很low。彆著急,lombok為我們解決了這個難題。

要想使用lombok,需要新增如下依賴:

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

使用也是很簡單,只需要在類上標註一個註解@Slf4j即可,如下:

@Slf4j
class DemoApplicationTests {
  @Test
  public void test(){
    log.debug("輸出DEBUG日誌.......");
  }
}

如何定製日誌級別?

Spring Boot中預設的日誌級別是INFO,但是可以自己定製日誌級別,如下:

logging.level.root=DEBUG

上面是將所有的日誌的級別都改成了DEBUG,Spring Boot還支援package級別的日誌級別調整,格式為:logging.level.xxx=xxx,如下:

logging.level.com.example.demo=INFO

那麼完整的配置如下:

logging.level.root=DEBUG
logging.level.com.example.demo=INFO

日誌如何輸出到檔案中?

Spring Boot中日誌預設是輸出到控制檯的,但是在生產環境中顯示不可行的,因此需要配置日誌輸出到日誌檔案中。

其中有兩個重要配置如下:

  1. logging.file.path:指定日誌檔案的路徑
  2. logging.file.name:日誌的檔名,預設為spring.log

注意:官方文件說這兩個屬性不能同時配置,否則不生效,因此只需要配置一個即可。

指定輸出的檔案為當前專案路徑的logs檔案下,預設生成的日誌檔案為spring.log,如下:

logging.file.path=./logs

日誌檔案中還有一些其他的屬性,比如日誌檔案的最大size,保留幾天的日誌等等,下面會介紹到。

如何定製日誌格式?

預設的日誌格式在第一張圖已經看到了,有時我們需要定製自己需要的日誌輸出格式,這樣在排查日誌的時候能夠一目瞭然。

定製日誌格式有兩個配置,分別是控制檯的輸出格式和檔案中的日誌輸出格式,如下:

  1. logging.pattern.console:控制檯的輸出格式
  2. logging.pattern.file:日誌檔案的輸出格式

例如配置如下:

logging.pattern.console=%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n
logging.pattern.file=%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n

上面的配置編碼的含義如下:

%d{HH:mm:ss.SSS}——日誌輸出時間

%thread——輸出日誌的程式名字,這在Web應用以及非同步任務處理中很有用

%-5level——日誌級別,並且使用5個字元靠左對齊

%logger- ——日誌輸出者的名字

%msg——日誌訊息

%n——平臺的換行符

如何自定義日誌配置?

Spring Boot官方文件指出,根據不同的日誌系統,可以按照如下的日誌配置檔名就能夠被正確載入,如下:

  1. Logback:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy
  2. Log4j:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml
  3. Log4j2:log4j2-spring.xml, log4j2.xml
  4. JDK (Java Util Logging):logging.properties

Spring Boot官方推薦優先使用帶有-spring的檔名作為你的日誌配置。因此只需要在src/resources資料夾下建立logback-spring.xml即可,配置檔案內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- 定義日誌存放目錄 -->
    <property name="logPath" value="logs"/>
    <!--    日誌輸出的格式-->
    <property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t-%L] %-5level %logger{36} %L %M - %msg%xEx%n"/>
    <contextName>logback</contextName>

    <!--輸出到控制檯 ConsoleAppender-->
    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
        <!--展示格式 layout-->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>${PATTERN}</pattern>
        </layout>
            <!--過濾器,只有過濾到指定級別的日誌資訊才會輸出,如果level為ERROR,那麼控制檯只會輸出ERROR日誌-->
<!--        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
<!--            <level>ERROR</level>-->
<!--        </filter>-->
    </appender>

    <!--正常的日誌檔案,輸出到檔案中-->
    <appender name="fileDEBUGLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--如果只是想要 Info 級別的日誌,只是過濾 info 還是會輸出 Error 日誌,因為 Error 的級別高,
        所以我們使用下面的策略,可以避免輸出 Error 的日誌-->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!--過濾 Error-->
            <level>Error</level>
            <!--匹配到就禁止-->
            <onMatch>DENY</onMatch>
            <!--沒有匹配到就允許-->
            <onMismatch>ACCEPT</onMismatch>
        </filter>

        <!--日誌名稱,如果沒有File 屬性,那麼只會使用FileNamePattern的檔案路徑規則
            如果同時有<File>和<FileNamePattern>,那麼當天日誌是<File>,明天會自動把今天
            的日誌改名為今天的日期。即,<File> 的日誌都是當天的。
        -->
        <File>${logPath}/log_demo.log</File>
        <!--滾動策略,按照時間滾動 TimeBasedRollingPolicy-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--檔案路徑,定義了日誌的切分方式——把每一天的日誌歸檔到一個檔案中,以防止日誌填滿整個磁碟空間-->
            <FileNamePattern>${logPath}/log_demo_%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--只保留最近90天的日誌-->
            <maxHistory>90</maxHistory>
            <!--用來指定日誌檔案的上限大小,那麼到了這個值,就會刪除舊的日誌-->
            <!--<totalSizeCap>1GB</totalSizeCap>-->
        </rollingPolicy>
        <!--日誌輸出編碼格式化-->
        <encoder>
            <charset>UTF-8</charset>
            <pattern>${PATTERN}</pattern>
        </encoder>
    </appender>

    <!--輸出ERROR日誌到指定的檔案中-->
    <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--如果只是想要 Error 級別的日誌,那麼需要過濾一下,預設是 info 級別的,ThresholdFilter-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>Error</level>
        </filter>
        <!--日誌名稱,如果沒有File 屬性,那麼只會使用FileNamePattern的檔案路徑規則
            如果同時有<File>和<FileNamePattern>,那麼當天日誌是<File>,明天會自動把今天
            的日誌改名為今天的日期。即,<File> 的日誌都是當天的。
        -->
        <File>${logPath}/error.log</File>
        <!--滾動策略,按照時間滾動 TimeBasedRollingPolicy-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--檔案路徑,定義了日誌的切分方式——把每一天的日誌歸檔到一個檔案中,以防止日誌填滿整個磁碟空間-->
            <FileNamePattern>${logPath}/error_%d{yyyy-MM-dd}.log</FileNamePattern>
            <!--只保留最近90天的日誌-->
            <maxHistory>90</maxHistory>
            <!--用來指定日誌檔案的上限大小,那麼到了這個值,就會刪除舊的日誌-->
            <!--<totalSizeCap>1GB</totalSizeCap>-->
        </rollingPolicy>
        <!--日誌輸出編碼格式化-->
        <encoder>
            <charset>UTF-8</charset>
            <pattern>${PATTERN}</pattern>
        </encoder>
    </appender>


    <!--指定最基礎的日誌輸出級別-->
    <root level="DEBUG">
        <!--appender將會新增到這個loger-->
        <appender-ref ref="consoleLog"/>
        <appender-ref ref="fileDEBUGLog"/>
        <appender-ref ref="fileErrorLog"/>
    </root>

    <!--    定義指定package的日誌級別-->
    <logger name="org.springframework" level="DEBUG"></logger>
    <logger name="org.mybatis" level="DEBUG"></logger>
    <logger name="java.sql.Connection" level="DEBUG"></logger>
    <logger name="java.sql.Statement" level="DEBUG"></logger>
    <logger name="java.sql.PreparedStatement" level="DEBUG"></logger>
    <logger name="io.lettuce.*" level="INFO"></logger>
    <logger name="io.netty.*" level="ERROR"></logger>
    <logger name="com.rabbitmq.*" level="DEBUG"></logger>
    <logger name="org.springframework.amqp.*" level="DEBUG"></logger>
    <logger name="org.springframework.scheduling.*" level="DEBUG"></logger>
    <!--定義com.xxx..xx..xx包下的日誌資訊不上傳,直接輸出到fileDEBUGLog和fileErrorLog這個兩個appender中,日誌級別為DEBUG-->
    <logger name="com.xxx.xxx.xx"  additivity="false" level="DEBUG">
        <appender-ref ref="fileDEBUGLog"/>
        <appender-ref ref="fileErrorLog"/>
    </logger>

</configuration>

當然,如果就不想用Spring Boot推薦的名字,想自己定製也行,只需要在配置檔案中指定配置檔名即可,如下:

logging.config=classpath:logging-config.xml

懵逼了,一堆配置什麼意思?彆著急,下面一一介紹。

configuration節點

這是一個根節點,其中的各個屬性如下:

  1. scan:當此屬性設定為true時,配置檔案如果發生改變,將會被重新載入,預設值為true。
  2. scanPeriod:設定監測配置檔案是否有修改的時間間隔,如果沒有給出時間單位,預設單位是毫秒。當scan為true時,此屬性生效。預設的時間間隔為1分鐘。
  3. debug:當此屬性設定為true時,將列印出logback內部日誌資訊,實時檢視logback執行狀態。預設值為false。

root節點

這是一個必須節點,用來指定基礎的日誌級別,只有一個level屬性,預設值是DEBUG。 該節點可以包含零個或者多個元素,子節點是appender-ref,標記這個appender將會新增到這個logger中。

contextName節點

標識一個上下文名稱,預設為default,一般用不到

property節點

標記一個上下文變數,屬性有name和value,定義變數之後可以使用${}來獲取。

appender節點

用來格式化日誌輸出節點,有兩個屬性nameclass,class用來指定哪種輸出策略,常用就是控制檯輸出策略檔案輸出策略

這個節點很重要,通常的日誌檔案需要定義三個appender,分別是控制檯輸出,常規日誌檔案輸出,異常日誌檔案輸出。

該節點有幾個重要的子節點,如下:

  1. filter:日誌輸出攔截器,沒有特殊定製一般使用系統自帶的即可,但是如果要將日誌分開,比如將ERROR級別的日誌輸出到一個檔案中,將除了ERROR級別的日誌輸出到另外一個檔案中,此時就要攔截ERROR級別的日誌了。
  2. encoder: 和pattern節點組合用於具體輸出的日誌格式和編碼方式。
  3. file: 節點用來指明日誌檔案的輸出位置,可以是絕對路徑也可以是相對路徑
  4. rollingPolicy: 日誌回滾策略,在這裡我們用了TimeBasedRollingPolicy,基於時間的回滾策略,有以下子節點fileNamePattern,必要節點,可以用來設定指定時間的日誌歸檔。
  5. maxHistory : 可選節點,控制保留的歸檔檔案的最大數量,超出數量就刪除舊檔案,,例如設定為30的話,則30天之後,舊的日誌就會被刪除
  6. totalSizeCap: 可選節點,用來指定日誌檔案的上限大小,例如設定為3GB的話,那麼到了這個值,就會刪除舊的日誌

logger節點

可選節點,用來具體指明包的日誌輸出級別,它將會覆蓋root的輸出級別。 該節點有幾個重要的屬性如下:

  1. name:指定的包名
  2. level:可選,日誌的級別
  3. addtivity:可選,預設為true,將此logger的資訊向上級傳遞,將有root節點定義日誌列印。如果設定為false,將不會上傳,此時需要定義一個appender-ref節點才會輸出。

總結

Spring Boot的日誌選型以及如何自定義日誌配置就介紹到這裡,如果覺得有所收穫,不妨點個關注,分享一波,將是對作者最大的鼓勵!!!

相關文章