Spring Boot (日誌篇):整合預設日誌logback
目錄
說在前面
作為開發,日誌是可以說是最重要,沒有之一的東西。有程式碼就一定要有日誌,日誌寫的越詳細,處理器bug來越簡單,解決問題也越容易,所以碼程式碼之前務必先理解日誌是怎麼生成的。
Spring Boot在所有內部日誌中使用Commons Logging,但是預設配置也提供了對常用日誌的支援,
如:java.util.logging,Apache log4j, log4j2,Logback,SLF4J即簡單日誌門面(Simple Logging Facade for Java),commons-logging, Spring框架使用的是Jakarta Commons Logging API (JCL)。
每種Logger都可以通過配置使用控制檯或者檔案輸出日誌內容。
logback(Spring Boot 預設日誌)
Logback是log4j框架的作者開發的新一代日誌框架,它效率更高、能夠適應諸多的執行環境,同時天然支援SLF4J。
預設情況下,Spring Boot會用Logback來記錄日誌,並用INFO級別輸出到控制檯。在執行應用程式和其他例子時,你應該已經看到很多INFO級別的日誌了。
從上圖可以看到,日誌輸出內容元素具體如下:
- 時間日期:精確到毫秒
- 日誌級別:ERROR, WARN, INFO, DEBUG or TRACE
- 程序ID
- 分隔符:— 標識實際日誌的開始
- 執行緒名:方括號括起來(可能會截斷控制檯輸出)
- Logger名:通常使用原始碼的類名
- 日誌內容
在pom.xml加入相關依賴
spring-boot-starter-logging
開啟之後:
可以明顯看到我們需要的logback。
當然,在真正開發中,很多時候不需要特別去考慮引用,為了避免依賴衝突,可以先看一下工程中有沒有已經在引用的。
比如:
spring-boot-starter-test 按住 CTRL 進去可以看到以下:
再繼續點開spring-boot-starter:
當然這裡面的version是父類引用的version。
日誌級別
日誌級別從低到高分為:
TRACE
<DEBUG
<INFO
<WARN
<ERROR
<FATAL
如果設定為 WARN
,則低於 WARN
的資訊都不會輸出。 Spring Boot
中預設配置ERROR
、WARN
和INFO
級別的日誌輸出到控制檯。
控制檯輸出
您還可以通過啟動您的應用程式 --debug
標誌來啟用“除錯”模式(開發的時候推薦開啟),以下兩種方式皆可:
- 在執行命令後加入
--debug
標誌,如:$ java -jar springTest.jar --debug
- 在
application.properties
中配置debug=true
,該屬性置為true
的時候,核心Logger
(包含嵌入式容器、hibernate、spring)會輸出更多內容,但是你自己應用的日誌並不會輸出為DEBUG
級別。
日誌類名必須為當前類SpringBootDemoApplicationTests,否則將會顯示其他類:
lombok方式
在pom.xml加入相關依賴:
安裝 Lombok Plugin:
允許log註解:
這樣就可以直接在對應的類上直接寫 @Slf4j,然後log直接使用:
日誌檔案輸出
預設情況下,Spring Boot將日誌輸出到控制檯,不會寫到日誌檔案。
使用Spring Boot
喜歡在application.properties
或application.yml
配置,這樣只能配置簡單的場景,儲存路徑、日誌格式等,複雜的場景(區分 info 和 error 的日誌、每天產生一個日誌檔案等)滿足不了,只能自定義配置,下面會演示。
儲存路徑
如果要編寫除控制檯輸出之外的日誌檔案,則需在application.properties
中設定logging.file
或logging.path
屬性。
logging.file
,設定檔案,可以是絕對路徑,也可以是相對路徑。如:logging.file=
springBootLogBack.log(注意字尾,務必有)logging.path
,設定目錄,會在該目錄下建立spring.log
檔案,並寫入日誌內容,如:logging.path=/log
如果只配置logging.file
,會在專案的當前路徑下生成一個xxx.log
日誌檔案。
如果只配置logging.path
,在/log
資料夾生成一個日誌檔案為spring.log
注:二者不能同時使用,如若同時使用,則只有
logging.file
生效
預設情況下,日誌檔案的大小達到10MB
時會切分一次,產生新的日誌檔案,預設級別為:ERROR、WARN、INFO
級別控制
所有支援的日誌記錄系統都可以在Spring
環境中設定記錄級別(例如在application.properties
中)
格式為:'logging.level.* = LEVEL'
logging.level
:日誌級別控制字首,*為包名或Logger名 LEVEL
:選項TRACE, DEBUG, INFO, WARN, ERROR, FATAL, OFF
舉例:
logging.level.com.example.demo.controller.LogController=info:LogController類中所有class以info級別輸出
logging.level.root=WARN:root日誌以WARN級別輸出
輸出格式
自定義日誌配置
根據不同的日誌系統,你可以按如下規則組織配置檔名,就能被正確載入:
- 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
的檔名作為你的日誌配置(如使用logback-spring.xml
,而不是logback.xml
),命名為logback-spring.xml
的日誌配置檔案,spring boot
可以為它新增一些spring boot
特有的配置項(下面會提到)。
預設的命名規則,並且放在 src/main/resources
下面即可
如果你即想完全掌控日誌配置,但又不想用logback.xml
作為Logback
配置的名字,application.yml
可以通過logging.config
屬性指定自定義的名字:logging.config=classpath:logging-config.xml
雖然一般並不需要改變配置檔案的名字,但是如果你想針對不同執行時Profile
使用不同的日誌配置,這個功能會很有用。
一般不需要這個屬性,而是直接在logback-spring.xml
中使用springProfile
配置,不需要logging.config
指定不同環境使用不同配置檔案。springProfile
配置在下面介紹。
根節點包含的屬性
- scan:當此屬性設定為
true
時,配置檔案如果發生改變,將會被重新載入,預設值為true
。 - scanPeriod:設定監測配置檔案是否有修改的時間間隔,如果沒有給出時間單位,預設單位是毫秒。當
scan
為true
時,此屬性生效。預設的時間間隔為1分鐘。 - debug:當此屬性設定為
true
時,將打印出logback
內部日誌資訊,實時檢視logback
執行狀態。預設值為false
。
根節點<configuration>
有2個屬性值,3個子節點,下面一一會詳細介紹。
屬性一:<contextName>
設定上下文名稱
每個logger都關聯到logger上下文,預設上下文名稱為“default”。但可以使用設定成其他名字,用於區分不同應用程式的記錄。一旦設定,不能修改,可以通過%contextName
來列印日誌上下文名稱,一般來說我們不用這個屬性,可有可無。
<contextName>logback-lvy</contextName>
屬性二:<property>
設定變數
用來定義變數值的標籤, 有兩個屬性,name和value;其中name的值是變數的名稱,value的值時變數定義的值。通過定義的值會被插入到logger上下文中。定義變數後,可以使“${}”來使用變數。
子節點一:<appender>新增器
appender用來格式化日誌輸出節點,有倆個屬性name和class,class用來指定哪種輸出策略,常用就是控制檯輸出策略和檔案輸出策略。
控制檯輸出ConsoleAppender
:
- 示例一:
Console顯示:
可以看到layout
和encoder
,都可以將事件轉換為格式化後的日誌記錄,但是控制檯輸出使用layout
,檔案輸出使用encoder。
- 示例二:
Console顯示:
<encoder>
表示對日誌進行編碼:
- %contextName:上下文名稱
- %d{"yyyy-MM-dd HH:mm:ss,SSS"}:日誌輸出時間
- %thread:輸出日誌的程序名字,這在Web應用以及非同步任務處理中很有用
- %-5level 或者 %-5p:日誌級別,並且使用5個字元靠左對齊
- %logger{36}:日誌輸出者的名字(從右邊數,長度為36),由於太長這裡引用的 %c{0}-%M
- %c{0}:日誌輸出者的名字,從右邊數,第一個(類名)
- %M:方法名
- %msg 或者%m:日誌訊息
- %n:換行符
當然也可以使用layout:
<!--輸出到控制檯 ConsoleAppender-->
<appender name="consoleLog1" class="ch.qos.logback.core.ConsoleAppender">
<!--展示格式 layout-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%contextName %d{"yyyy-MM-dd HH:mm:ss,SSS"} [%thread] [%-5p] [%c{0}-%M] - %m%n</pattern>
</layout>
</appender>
如果不想輸出某級別日誌,可以選擇ThresholdFilter為系統定義的攔截器,例如我們用ThresholdFilter來過濾掉ERROR級別以下的日誌不輸出到檔案中。如果不用記得註釋掉,不然你控制檯會發現沒日誌~
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
輸出到檔案 RollingFileAppender:
另一種常見的日誌輸出到檔案,隨著應用的執行時間越來越長,日誌也會增長的越來越多,將他們輸出到同一個檔案並非一個好辦法。RollingFileAppender
用於切分檔案日誌:
一些配置:
infoLogFile:
errorLogFile:
最後,root節點無比引用,否則寫的都無效了:
如果同時有<File>
和<FileNamePattern>
,根據日期分割日誌,程式碼註釋寫的很清楚了。
如果沒有<File>,那麼指揮使用<FileNamePattern>的檔案路徑規則。
如果要區分 Info
和 Error
級別的日誌,那麼需要使用過濾規則的策略。
子節點二:<root>根節點
level:用來設定列印級別,大小寫無關。
TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能設定為INHERITED或者同義詞NULL。 預設是DEBUG。
可以包含零個或多個元素,標識這個appender將會新增到這個logger。
子節點三:<loger>
<loger>
用來設定某一個包或者具體的某一個類的日誌列印級別、以及指定<appender>
。<loger>
僅有一個name
屬性,一個可選的level
和一個可選的addtivity
屬性。
name
:用來指定受此loger約束的某一個包或者具體的某一個類。level
:用來設定列印級別,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,還有一個特俗值INHERITED或者同義詞NULL,代表強制執行上級的級別。如果未設定此屬性,那麼當前loger將會繼承上級的級別。addtivity
:是否向上級loger傳遞列印資訊。預設是true。
loger在實際使用的時候有兩種情況
先來看一看程式碼中如何使用
這是一個登入的判斷的方法,我們引入日誌,並且列印不同級別的日誌,然後根據logback-spring.xml中的配置來看看列印了哪幾種級別日誌。
第一種:帶有loger
的配置,不指定級別,不指定appender
logback-spring.xml
增加 loger
配置如下:
<logger name="com.example.demo.controller.LogController" />
將控制controller
包下的所有類的日誌的列印,但是並沒用設定列印級別,所以繼承他的上級的日誌級別“info”
;
沒有設定addtivity
,預設為true,將此loger
的列印資訊向上級傳遞;
沒有設定appender
,此loger
本身不列印任何資訊。 <root level="info">
將root
的列印級別設定為“info”
,指定了名字為“console”
的appender
。
當執行com.example.demo.controller.LogController
類的login
方法時,LogController
在包com.example.demo.controller
中,所以首先執行<logger name="com.example.demo.controller.LogController"/>
,將級別為“info”
及大於“info”
的日誌資訊傳遞給root
,本身並不列印; root
接到下級傳遞的資訊,交給已經配置好的名為“console”的appender
處理,“console”
appender
將資訊列印到控制檯;
列印結果如下:
第二種:帶有多個loger
的配置,指定級別,指定appender
logback-spring.xml
增加 loger
配置如下:
控制com.example.demo.controller.LogController
類的日誌列印,列印級別為“WARN
”; additivity
屬性為false
,表示此loger
的列印資訊不再向上級傳遞;
指定了名字為“console
”的appender
;
這時候執行com.example.demo.controller.LogController
類的login方法時,先執行<logger name="com.example.demo.controller.LogController" level="WARN" additivity="false">
,將級別為“WARN
”及大於“WARN”的日誌資訊交給此loger
指定的名為“console
”的appender
處理,在控制檯中打出日誌,不再向上級root
傳遞列印資訊。
列印結果如下:
當然如果你把additivity="false"
改成additivity="true"
的話,就會列印兩次,因為列印資訊向上級傳遞,logger本身列印一次,root接到後又列印一次。
當然如果你把additivity="false"
改成additivity="true"
的話,就會列印兩次,因為列印資訊向上級傳遞,logger本身列印一次,root接到後又列印一次。
注意:
範圍有重疊的話,範圍小的,有效。
總結
到此為止終於介紹完日誌框架了,平時使用的時候推薦用自定義logback-spring.xml來配置,程式碼中使用日誌也很簡單,類裡面新增private final Logger logger = LoggerFactory.getLogger(Logger.class);
即可。
當然也可以使用lombok方式。
原始碼下載
[相關示例完整程式碼]請獲取 相關分支哦:feature-20180906-logBack