Spring Boot 第三彈,一文帶你了解日誌如何配置?
- 2020 年 9 月 29 日
- 筆記
- JAVA, springboot, 碼猿技術專欄
前言
日誌通常不會在需求階段作為一個功能單獨提出來,也不會在產品方案中看到它的細節。但是,這絲毫不影響它在任何一個系統中的重要的地位。
今天就來介紹一下Spring Boot中的日誌如何配置。
Spring Boot 版本
本文基於的Spring Boot的版本是2.3.4.RELEASE
。
日誌級別
幾種常見的日誌級別由低到高分為:TRACE < DEBUG < INFO < WARN < ERROR < FATAL
。
如何理解這個日誌級別呢?很簡單,如果項目中的日誌級別設置為INFO
,那麼比它更低級別的日誌資訊就看不到了,即是TRACE
、DEBUG
日誌將會不顯示。
日誌框架有哪些?
常見的日誌框架有log4j
、logback
、log4j2
。
log4j
這個日誌框架顯示是耳熟能詳了,在Spring開發中是經常使用,但是據說log4j官方已經不再更新了,而且在性能上比logback
、log4j2
差了很多。
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
,啟動項目日誌列印如下:
從上圖可以看出,輸出的日誌的默認元素如下:
-
時間日期:精確到毫秒 -
日誌級別:ERROR, WARN, INFO, DEBUG , TRACE -
進程ID -
分隔符:— 標識實際日誌的開始 -
執行緒名:方括弧括起來(可能會截斷控制台輸出) -
Logger名:通常使用源程式碼的類名 -
日誌內容
程式碼中如何使用日誌?
在業務中肯定需要追溯日誌,那麼如何在自己的業務中輸出日誌呢?其實常用的有兩種方式,下面一一介紹。
第一種其實也是很早之前常用的一種方式,只需要在程式碼添加如下:
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中日誌默認是輸出到控制台的,但是在生產環境中顯示不可行的,因此需要配置日誌輸出到日誌文件中。
其中有兩個重要配置如下:
-
logging.file.path
:指定日誌文件的路徑 -
logging.file.name
:日誌的文件名,默認為spring.log
注意:官方文檔說這兩個屬性不能同時配置,否則不生效,因此只需要配置一個即可。
指定輸出的文件為當前項目路徑的logs
文件下,默認生成的日誌文件為spring.log
,如下:
logging.file.path=./logs
日誌文件中還有一些其他的屬性,比如日誌文件的最大size,保留幾天的日誌等等,下面會介紹到。
如何訂製日誌格式?
默認的日誌格式在第一張圖已經看到了,有時我們需要訂製自己需要的日誌輸出格式,這樣在排查日誌的時候能夠一目了然。
訂製日誌格式有兩個配置,分別是控制台的輸出格式和文件中的日誌輸出格式,如下:
-
logging.pattern.console
:控制台的輸出格式 -
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官方文檔指出,根據不同的日誌系統,可以按照如下的日誌配置文件名就能夠被正確載入,如下:
-
Logback
:logback-spring.xml, logback-spring.groovy, logback.xml, logback.groovy -
Log4j
:log4j-spring.properties, log4j-spring.xml, log4j.properties, log4j.xml -
Log4j2
:log4j2-spring.xml, log4j2.xml -
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節點
這是一個根節點,其中的各個屬性如下:
-
scan
:當此屬性設置為true時,配置文件如果發生改變,將會被重新載入,默認值為true。 -
scanPeriod
:設置監測配置文件是否有修改的時間間隔,如果沒有給出時間單位,默認單位是毫秒。當scan為true時,此屬性生效。默認的時間間隔為1分鐘。 -
debug
:當此屬性設置為true時,將列印出logback內部日誌資訊,實時查看logback運行狀態。默認值為false。
root節點
這是一個必須節點,用來指定基礎的日誌級別,只有一個level
屬性,默認值是DEBUG
。
該節點可以包含零個或者多個元素,子節點是appender-ref
,標記這個appender
將會添加到這個logger中。
contextName節點
標識一個上下文名稱,默認為default,一般用不到
property節點
標記一個上下文變數,屬性有name和value,定義變數之後可以使用${}
來獲取。
appender節點
用來格式化日誌輸出節點,有兩個屬性name
和class
,class用來指定哪種輸出策略,常用就是控制台輸出策略和文件輸出策略。
這個節點很重要,通常的日誌文件需要定義三個appender,分別是控制台輸出,常規日誌文件輸出,異常日誌文件輸出。
該節點有幾個重要的子節點,如下:
-
filter
:日誌輸出攔截器,沒有特殊訂製一般使用系統自帶的即可,但是如果要將日誌分開,比如將ERROR級別的日誌輸出到一個文件中,將除了ERROR
級別的日誌輸出到另外一個文件中,此時就要攔截ERROR
級別的日誌了。 -
encoder
: 和pattern節點組合用於具體輸出的日誌格式和編碼方式。 -
file
: 節點用來指明日誌文件的輸出位置,可以是絕對路徑也可以是相對路徑 -
rollingPolicy
: 日誌回滾策略,在這裡我們用了TimeBasedRollingPolicy,基於時間的回滾策略,有以下子節點fileNamePattern,必要節點,可以用來設置指定時間的日誌歸檔。 -
maxHistory
: 可選節點,控制保留的歸檔文件的最大數量,超出數量就刪除舊文件,,例如設置為30的話,則30天之後,舊的日誌就會被刪除 -
totalSizeCap
: 可選節點,用來指定日誌文件的上限大小,例如設置為3GB的話,那麼到了這個值,就會刪除舊的日誌
logger節點
可選節點,用來具體指明包的日誌輸出級別,它將會覆蓋root的輸出級別。
該節點有幾個重要的屬性如下:
-
name
:指定的包名 -
level
:可選,日誌的級別 -
addtivity
:可選,默認為true,將此logger的資訊向上級傳遞,將有root節點定義日誌列印。如果設置為false,將不會上傳,此時需要定義一個appender-ref
節點才會輸出。
總結
Spring Boot的日誌選型以及如何自定義日誌配置就介紹到這裡,如果覺得有所收穫,不妨點個關注,分享一波,將是對作者最大的鼓勵!!!
