Spring Boot(二)——Spring Boot日誌
一、日誌框架
在Java中,輸出日誌需要使用一個或者多個日誌框架,這些框架提供了必要的物件、方法和配置來傳輸訊息。Java在java.util.logging包中提供了一個預設的框架。除此之外,還有很多其它第三方框架,包括Log4j、Logback以及tinylog。還有其它一些開發包,例如SLF4J和Apache Commons Logging,它們提供了一些抽象層,對你的程式碼和日誌框架進行解耦,從而允許你在不同的日誌框架中進行切換。
如何選擇一個日誌解決方案,這取決於你的日誌需求的複雜度、和其它日誌解決方案的相容性、易用性以及個人喜好。Logback基於log4j之前的版本開發(版本1),因此它們的功能集合都非常類似。然而,Log4j在最新版本(版本2)中引用了一些改進,例如支援多API,並提升了在用Disruptor庫的效能。
抽象層(日誌門面)
諸如SLF4J這樣的抽象層,會將你的應用程式從日誌框架中解耦。應用程式可以在執行時選擇繫結到一個特定的日誌框架(例如java.util.logging、Log4j或者Logback),這通過在應用程式的類路徑中新增對應的日誌框架來實現。如果在類路徑中配置的日誌框架不可用,抽象層就會立刻取消呼叫日誌的相應邏輯。抽象層可以讓我們更加容易地改變專案現有的日誌框架,或者整合那些使用了不同日誌框架的專案。
二、Spring Boot預設日誌
Spring Boot預設的日誌抽象層
SLF4J——Simple Logging Facade For Java,它是一個針對於各類Java日誌框架的統一Facade抽象。Java日誌框架眾多——常用的有java.util.logging, log4j, logback,commons-logging, Spring框架使用的是Jakarta Commons Logging API (JCL)。而SLF4J定義了統一的日誌抽象介面,而真正的日誌實現則是在執行時決定的——它提供了各類日誌框架的binding。
Spring Boot預設的日誌實現層
Logback是log4j框架的作者開發的新一代日誌框架,它效率更高、能夠適應諸多的執行環境,同時天然支援SLF4J。
注: 預設情況下,Spring Boot會用Logback來記錄日誌,並用INFO級別輸出到控制檯。
三、Spring Boot日誌配置
Spring Boot官方推薦優先使用帶有 -spring 的檔名作為你的日誌配置(如使用logback-spring.xml),命名為logback-spring.xml
的日誌配置檔案,spring boot可以為它新增一些spring boot特有的配置項(如,springProfile等)。
下面是Spring Boot自定義日誌配置檔案的解析:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--定義日誌存放的位置-->
<springProperty scope="context" name="gunsLogPath" source="log.path"
defaultValue="guns-logs"/>
<!-- ****************************************************************************************** -->
<!-- ****************************** 本地開發只在控制檯列印日誌 ************************************ -->
<!-- ****************************************************************************************** -->
<springProfile name="local">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--encoder 預設配置為PatternLayoutEncoder-->
<encoder>
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
<logger name="com.stylefeng.guns" level="debug" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
</springProfile>
<!-- ****************************************************************************************** -->
<!-- ********************** 放到伺服器上不管在什麼環境都只在檔案記錄日誌 **************************** -->
<!-- ****************************************************************************************** -->
<springProfile name="!local">
<!-- 日誌記錄器,日期滾動記錄 -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在記錄的日誌檔案的路徑及檔名 -->
<file>${gunsLogPath}/log_error.log</file>
<!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 歸檔的日誌檔案的路徑,例如今天是2013-12-21日誌,當前寫的日誌檔案路徑為file節點指定,可以將此檔案與file指定檔案路徑設定為不同路徑,從而將當前日誌檔案或歸檔日誌檔案置不同的目錄。
而2013-12-21的日誌檔案在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${gunsLogPath}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日誌記錄之外,還配置了日誌檔案不能超過2M,若超過2M,日誌檔案會以索引0開始,
命名日誌檔案,例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式記錄日誌 -->
<append>true</append>
<!-- 日誌檔案的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日誌檔案只記錄error級別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<!-- 日誌記錄器,日期滾動記錄 -->
<appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在記錄的日誌檔案的路徑及檔名 -->
<file>${gunsLogPath}/log_total.log</file>
<!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 歸檔的日誌檔案的路徑,例如今天是2013-12-21日誌,當前寫的日誌檔案路徑為file節點指定,可以將此檔案與file指定檔案路徑設定為不同路徑,從而將當前日誌檔案或歸檔日誌檔案置不同的目錄。
而2013-12-21的日誌檔案在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${gunsLogPath}/total/log-total-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日誌記錄之外,還配置了日誌檔案不能超過2M,若超過2M,日誌檔案會以索引0開始,
命名日誌檔案,例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式記錄日誌 -->
<append>true</append>
<!-- 日誌檔案的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<root level="info">
<appender-ref ref="FILE_ERROR"/>
<appender-ref ref="FILE_ALL"/>
</root>
</springProfile>
</configuration>
注:以上程式碼來自碼雲開源框架guns
根節點<configuration>
包含的屬性
scan:當此屬性設定為true時,配置檔案如果發生改變,將會被重新載入,預設值為true。
scanPeriod:設定監測配置檔案是否有修改的時間間隔,如果沒有給出時間單位,預設單位是毫秒。當scan為true時,此屬性生效。預設的時間間隔為1分鐘。
debug:當此屬性設定為true時,將打印出logback內部日誌資訊,實時檢視logback執行狀態。預設值為false。
<springProperty>
標籤
用來定義變數值的標籤, 有兩個屬性,name和value;其中name的值是變數的名稱,value的值時變數定義的值。通過定義的值會被插入到logger上下文中。定義變數後,可以使“${}”來使用變數。
<file>${gunsLogPath}/log_error.log</file>
<appender>
標籤
appender用來格式化日誌輸出節點,有倆個屬性name和class,class用來指定哪種輸出策略,常用就是控制檯輸出策略和檔案輸出策略。
輸出到控制檯(ConsoleAppender)
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--encoder 預設配置為PatternLayoutEncoder-->
<encoder>
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
輸出到檔案(RollingFileAppender)
<!-- 日誌記錄器,日期滾動記錄 -->
<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在記錄的日誌檔案的路徑及檔名 -->
<file>${gunsLogPath}/log_error.log</file>
<!-- 日誌記錄器的滾動策略,按日期,按大小記錄 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 歸檔的日誌檔案的路徑,例如今天是2013-12-21日誌,當前寫的日誌檔案路徑為file節點指定,可以將此檔案與file指定檔案路徑設定為不同路徑,從而將當前日誌檔案或歸檔日誌檔案置不同的目錄。
而2013-12-21的日誌檔案在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${gunsLogPath}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 除按日誌記錄之外,還配置了日誌檔案不能超過2M,若超過2M,日誌檔案會以索引0開始,
命名日誌檔案,例如log-error-2013-12-21.0.log -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!-- 追加方式記錄日誌 -->
<append>true</append>
<!-- 日誌檔案的格式 -->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>===%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %logger Line:%-3L - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!-- 此日誌檔案只記錄error級別的 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
<encoder>
標籤
<encoder>
表示對日誌進行編碼:
- %d{yyyy-MM-dd HH:mm:ss.SSS}——日誌輸出時間
- %thread——輸出日誌的程序名字,這在Web應用以及非同步任務處理中很有用
- %-5level——日誌級別,並且使用5個字元靠左對齊
- %logger——日誌輸出者的名字
- %msg——日誌訊息
- %n——平臺的換行符
<filter>
標籤
此日誌檔案只記錄error級別的
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>error</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<root>
標籤
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
<root>
標籤是必選的,用來指定最基礎的日誌輸出級別,只有一個level屬性。
level: 用來設定列印級別,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能設定為INHERITED或者同義詞NULL。預設是DEBUG。可以包含零個或多個元素,標識這個appender將會新增到這個logger。
<logger>
標籤
<logger name="com.stylefeng.guns" level="debug" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
<logger>
用來設定某一個包或者具體的某一個類的日誌列印級別、以及指定<appender>
。<logger>
僅有一個name屬性,一個可選的level和一個可選的addtivity屬性。
name:用來指定受此loger約束的某一個包或者具體的某一個類。
level:用來設定列印級別,大小寫無關:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,還有一個特俗值INHERITED或者同義詞NULL,代表強制執行上級的級別。如果未設定此屬性,那麼當前loger將會繼承上級的級別。
addtivity:是否向上級loger傳遞列印資訊。預設是true。
<springProfile>
標籤
<springProfile>
標籤為多環境日誌輸出,是Spring Boot自帶的配置屬性。
四、參考資料
Java日誌終極指南
Java日誌框架那些事兒(上)
Java日誌框架那些事兒(下)
Spring Boot 日誌配置(超詳細)
Spring Boot乾貨系列:(七)預設日誌logback配置解析