javascript
SpringBoot 项目使用 SLF4J+logback 进行日志记录,来增强可维护性
作者:云深不知處
blog.csdn.net/mu_wind/article/details/99830829
SpringBoot會默認使用logback作為日志框架,在生成springboot項目的時候可以直接勾選logback,那么就可以直接使用logback了。手動添加的話,建議使用slf4j+logback,后面項目更容易維護:
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.21</version> </dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.1.7</version> </dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.1.7</version> </dependency>SLF4J 是一個用于日志系統的簡單Facade,允許最終用戶在部署其應用時使用其所希望的日志系統。大概意思是指你只需要按統一的方式寫記錄日志的代碼,而無需關心日志是通過哪個日志系統,以什么風格輸出的,因為它們取決于部署項目時綁定的日志系統。
例如,在項目中使用了 SLF4J 記錄日志,并且綁定了 Log4j(即導入相應的依賴),則日志會以 Log4j 的風格輸出;后期需要改為以 Logback 的風格輸出日志,只需要將 Log4j 替換成 Logback 即可,不用修改項目中的代碼。
1 快速實現
假如我們需要實現這么一個需求:在文件中記錄調用接口事件和傳參,并在控制臺顯示。實現起來很簡單,三步即可。
第一步,在resource目錄下創建一個logback.xml文件,內部寫入:
<?xml?version='1.0'?encoding='UTF-8'?> <!--日志配置--> <configuration><!--直接定義屬性--><property?name="logFile"?value="logs/mutest"/><property?name="maxFileSize"?value="30MB"/><!--控制臺日志--><appender?name="STDOUT"?class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d?[%thread]?%-5level?%logger{50}?-[%file:%line]-?%msg%n</pattern><charset>UTF-8</charset></encoder></appender><!--滾動文件日志--><appender?name="fileLog"?class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${logFile}.log</file><encoder><!--日志輸出格式--><pattern>%d?[%thread]?%-5level?-[%file:%line]-?%msg%n</pattern><charset>UTF-8</charset></encoder><rollingPolicy?class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>${logFile}.%d{yyyy-MM-dd}.%i.log</fileNamePattern><maxFileSize>${maxFileSize}</maxFileSize></rollingPolicy></appender><!--創建一個具體的日志輸出--><logger?name="com.mutest"?level="info"?additivity="true"><!--可以有多個appender-ref,即將日志記錄到不同的位置--><appender-ref?ref="STDOUT"/><appender-ref?ref="fileLog"/></logger><!--基礎的日志輸出--><root?level="info"></root> </configuration>關于這段xml的詳情,第二章節會詳細講解
第二步,在application.yml文件中配置項目要使用的日志配置文件路徑:
logging:config:?classpath:logback.xml第三步,在接口添加日志記錄:
import?org.slf4j.Logger; import?org.slf4j.LoggerFactory; import?org.springframework.web.bind.annotation.RequestMapping; import?org.springframework.web.bind.annotation.RequestMethod; import?org.springframework.web.bind.annotation.RestController;@RestController public?class?TestController?{//?getLogger()的入參是當前類,否則輸出日志的類名會是錯誤的private?final?Logger?logger?=?LoggerFactory.getLogger(TestController.class);@RequestMapping(value?=?"/test",?method?=?RequestMethod.GET)public?String?logTest(String?name,?String?age)?{logger.info("logTest,name:{},age:{}",?name,?age);return?"success";} }當然,如果你安裝了lombok這個插件,就更簡單了:
https://blog.csdn.net/mu_wind/article/details/104844946
import?lombok.extern.slf4j.Slf4j; import?org.springframework.web.bind.annotation.RequestMapping; import?org.springframework.web.bind.annotation.RequestMethod; import?org.springframework.web.bind.annotation.RestController;@RestController @Slf4j public?class?TestController?{@RequestMapping(value?=?"/test",?method?=?RequestMethod.GET)public?String?logTest(String?name,?String?age)?{log.info("logTest,name:{},age:{}",?name,?age);return?"success";} }啟動項目后調用接口,控制臺輸出如我們所期望:
同時,項目中增加了一個log目錄,生成mutest.log文件,里面記錄了日志:
功能是實現了,但我們腦子里還是有很多小問號,不急,接下來就細細講來。
2 配置xml
首先,在resource目錄下創建一個文件,命名為logback.xml。現在先向里面寫一些固定的內容,就是下面這個樣子:
<?xml?version='1.0'?encoding='UTF-8'?> <!--日志配置--> <configuration><!--直接定義屬性--><property?name=""?value=""/><!--通過配置文件定義屬性--><springProperty?name=""?source=""/><!--定義并描述一個日志的輸出屬性--><appender?name=""?class=""></appender><!--創建一個具體的日志輸出--><logger?name=""?level=""?additivity=""><appender-ref?ref=""/></logger><!--基礎的日志輸出--><root?level=""><appender-ref?ref=""/></root> </configuration> 在這里插入圖片描述2.1 configuration
<configuration>是logback.xml這個xml文件的根節點,它包含以下屬性:
scan:當此屬性設置為true時,配置文件如果發生改變,將會被重新加載,默認值為true。
scanPeriod:設置監測配置文件是否有修改的時間間隔,如果沒有給出時間單位,默認單位是毫秒。當scan為true時,此屬性生效。默認的時間間隔為1分鐘。
debug:當此屬性設置為true時,將打印出logback內部日志信息,實時查看logback運行狀態。默認值為false。
例如,下面這個configuration:
<configuration?scan="true"?scanPeriod="60?seconds"?debug="false">??<!--?其他配置省略-->?? </configuration>??2.2 property和springProperty
這兩個節點可以設置全局變量。
property可以直接設置,例如:
<property?name="logFile"?value="logs/mutest"/>這樣就設置了一個名為logFile的變量,后續通過${logFile}的方式就引用到了其值logs/mutest。
而springProperty則要配合配置文件,例如:
<springProperty?name="logFile"?source="log.file"/>也是設置了一個名為logFile的變量,但沒有直接賦值,而是通過source指向了配置文件的路徑,配置文件中是這樣的:
log:file:?logs/mutest2.3 root
root節點,必選節點,用來指定最基礎的日志輸出級別并指定<appender>,可以理解為根logger。
一個典型的root節點如下:
<root?level="debug"><appender-ref?ref="console"?/><appender-ref?ref="file"?/> </root>2.4 appender
appender節點是非常關鍵的一個節點,負責格式化一個日志輸出節點(也就是描述日志存儲類型、位置、滾動規則等屬性)。我個人理解,appender作用類似于構造一個日志模板,而logger是真正的日志輸出者,使用某個appender作為模板去寫日志。
appender有三種類型,分別是ConsoleAppender(控制臺日志)、FileAppender(文件日志)、RollingFileAppender(滾動文件日志)。
搜索Java知音公眾號,回復“后端面試”,送你一份Java面試題寶典.pdf
2.4.1 ConsoleAppender
ConsoleAppender的作用是將日志輸出到控制臺,一般在本地調試時使用,它的配置非常簡單,一個典型的ConsoleAppender如下:
<appender?name="STDOUT"?class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d?[%thread]?%-5level?%logger{50}?-[%file:%line]-?%msg%n</pattern><charset>UTF-8</charset></encoder> </appender>appender?有name和class兩個屬性:
name:appender節點的名稱,在后文中被logger節點引用。一個logback配置文件中不能有重復的appender name。
class:使用何種日志輸出策略,分別是ConsoleAppender(控制臺日志)、FileAppender(文件日志)、RollingFileAppender(滾動文件日志)。
2.4.2 FileAppender
FileAppender用于把日志添加到文件。一個典型的FileAppender如下:
<appender?name="FILE"?class="ch.qos.logback.core.FileAppender">?<file>testFile.log</file>?<append>true</append>?<encoder>?<pattern>%-4relative?[%thread]?%-5level?%logger{35}?-?%msg%n</pattern>?</encoder> </appender>?相對于ConsoleAppender,它多了一些子節點,讓我們一一來看:
<file>:被寫入的文件名,可以是相對目錄,也可以是絕對目錄,如果上級目錄不存在會自動創建,沒有默認值。
<append>:如果是?true,日志被追加到文件結尾,如果是?false,清空現存文件,默認是true。
<encoder>:對記錄事件進行格式化。(具體參數稍后講解 )
<prudent>:如果是?true,日志會被安全的寫入文件,即使其他的FileAppender也在向此文件做寫入操作,效率低,默認是?false。
<pattern>:日志的輸出格式。
pattern定義了日志的輸出格式,我們以<pattern>%d [%thread] %-5level -[%file:%line]- %msg%n</pattern>為例,分解開來:
%date:表示日期
%thread:表示線程名
%-5level:表示級別從左顯示 5 個字符寬度
%logger{50}:表示 Logger 名字最長 50 個字符
%msg:表示日志消息
%n:換行符
2.4.3 RollingFileAppender
RollingFileAppender用于滾動記錄文件,先將日志記錄到指定文件,當符合某個條件時,將日志記錄到其他文件。一個典型的RollingFileAppender節點如下:
<configuration><!--直接定義屬性--><property?name="logFile"?value="logs/mutest"/><property?name="maxFileSize"?value="30MB"/><appender?name="fileLog"?class="ch.qos.logback.core.rolling.RollingFileAppender"><!--日志文件存儲路徑,來自property設置--><file>${logFile}.log</file><encoder><pattern>%d?[%thread]?%-5level?-[%file:%line]-?%msg%n</pattern><charset>UTF-8</charset></encoder><rollingPolicy?class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!--每天生成一個新的活動日志文件,舊的日志歸檔,后綴名為2019.08.12這種格式--><fileNamePattern>${logFile}.%d{yyyy-MM-dd}.%i.log</fileNamePattern><!--活動日志文件最大值,超過這個值將產生新日志文件--><maxFileSize>${maxFileSize}</maxFileSize><!--只保留最近30天的日志--><maxHistory>30</maxHistory><!--用來指定日志文件的上限大小,那么到了這個值,就會刪除舊的日志--><totalSizeCap>1GB</totalSizeCap></rollingPolicy><!--用來指定日志文件的上限大小,那么到了這個值,就會刪除舊的日志--><filter?class="ch.qos.logback.classic.filter.LevelFilter"><level>error</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter></appender> </configuration>另外,RollingFileAppender節點下有一些常用的子節點:
<rollingPolicy>:當發生滾動時,決定 RollingFileAppender 的行為,涉及文件移動和重命名。
<filter>:日志輸出攔截器,可以自定義攔截器也可以用系統一些定義好的攔截器。
<rollingPolicy>:當發生滾動時,決定RollingFileAppender的行為,涉及文件移動和重命名。屬性class定義具體的滾動策略類。
SizeAndTimeBasedRollingPolicy:根據日志文件大小和時間周期作為切分條件,滿足其中任意一個就要做切分。maxFileSize的值決定了當天的日志文件大小上限,超過這個上限,同一天將會有多個日志文件,因此<fileNamePattern>${logFile}.%d{yyyy-MM-dd}.%i</fileNamePattern>中有一個%i,就是為應對同一天生成多個日志文件而寫,在日志量很大的情況下,會出現mutest.log.2020-07-28.0.log、mutest.2020-07-28.1.log這種情況。
TimeBasedRollingPolicy:只以時間周期為切分條件,在這種策略下,存檔日志名稱格式設置為<fileNamePattern>${logFile}.%d{yyyy-MM-dd}.log</fileNamePattern>即可。
SizeBasedTriggeringPolicy:只以文件大小為切分條件,在這種策略下,<maxFileSize>日志滾動的唯一觸發條件。
<fileNamePattern>:必要節點。以${logFile}.%d{yyyy-MM-dd}.%i.log為例(mutest.2019-07-28.0.log),有這么幾個部分:
${logFile}:固定文件名稱前綴,這里是引用了<property>中設置的變量。
%d{yyyy-MM}:指定日志名稱中間日期的格式,如果只有%d,將默認使用yyyy-MM-dd格式。
%i:當日志量過大,導致同一天生成兩個及以上日志文件時,這個屬性將為日志名稱加一個索引作為后綴,以加以區分。
.log.zip:指定存檔日志文件的壓縮格式。
還有幾個屬性,要根據滾動策略去添加:
<maxFileSize>:這是活動文件的大小,SizeAndTimeBasedRollingPolicy策略和SizeBasedTriggeringPolicy策略下必須有。默認值是10MB。超過這個大小,就要生成新的活動文件了。
<maxHistory>:可選節點,控制保留的歸檔文件的最大數量,超出數量就刪除舊文件。假設設置每個月滾動,且<maxHistory>是6,則只保存最近6個月的文件,刪除之前的舊文件。注意,刪除舊文件是,那些為了歸檔而創建的目錄也會被刪。
<totalSizeCap>:可選節點,表示日志文件總大小超過1GB將刪除存檔日志文件。
2.5 logger
logger節點,可選節點,作用是指明具體的包或類的日志輸出級別,以及要使用的<appender>(可以把<appender>理解為一個日志模板)。
一個典型的logger節點如下:
<!--?name?屬性表示匹配的logger類型前綴?-->?? <logger?name="com.mutest.demo">??<level?value="INFO"?/>??<!--?引用的appender,類似于spring的ref?-->??<appender-ref?ref="fileLog"?/>??<appender-ref?ref="STDOUT"?/>? </logger>??name:必寫屬性,指定具體包或類,被指定的包或類中的日志輸出將遵從該logger規定配置。
level:非必寫屬性,指定日志輸出級別,該級別將覆蓋root配置的輸出級別。
addtivity:非必寫屬性,是否向上級loger傳遞打印信息。默認是true。
appender-ref:引用的appender,引用后將實現appender中定義的行為,例如上面示例中引用了fileLog這個appender,那么com.mutest.demo中打印的日志將按fileLog的配置進行記錄。一個logger可以有多個引用,互不影響。
3 更多情形
3.1 日志級別
logback有5種級別,分別是TRACE < DEBUG < INFO < WARN < ERROR,定義于ch.qos.logback.classic.Level類中。
Trace:是追蹤,就是程序推進一下,你就可以寫個trace輸出,所以trace應該會特別多,一般不會設置到這個級別。
Debug:指出細粒度信息事件對調試應用程序是非常有幫助的。
Info:消息在粗粒度級別上突出強調應用程序的運行過程。
Warn:輸出警告及warn以上級別的日志。
Error:輸出錯誤信息日志.
此外OFF表示關閉全部日志,ALL表示開啟全部日志。
那么,在logback中,日志級別如何設置呢?
首先,<root>中可以設置日志級別,如果不設置,root logger默認級別是DEBUG。
?<root?level="info"></root>其次,logger中可以設置日志級別,設置后將覆蓋<root>的設置,不設置將繼承<root>的日志級別
<logger?name="com.mutest"?level="error"?additivity="false"><appender-ref?ref="STDOUT"/><appender-ref?ref="fileLog"/> </logger>另外,還可以在配置文件中設置更加具體的日志級別,例如將com.mutest.controller包下所有的日志輸出級別設置為info,那么即使logger中,設置為error級別,日志仍然輸出。
logging:config:?classpath:logback.xmllevel:com.mutest.controller:?info3.2 日志滾動
如果不設置日志滾動策略,那么會一直向一個文件中追加日志,日志文件會越來越大,想要查找有用信息會很慢,而且有占滿磁盤的風險。所以,我們要設置滾動策略,即滿足一定條件,生成一個新文件,而舊日志文件進行歸檔。
搜索Java知音公眾號,回復“后端面試”,送你一份Java面試題寶典.pdf
3.2.1 時間策略
以時間周期為切分條件,<rollingPolicy>的class要設置為ch.qos.logback.core.rolling.TimeBasedRollingPolicy,一個典型示例(每天生成一個日志文件,保存30天的日志文件)如下:
<configuration>?<appender?name="FILE"?class="ch.qos.logback.core.rolling.RollingFileAppender">?<rollingPolicy?class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">?<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>?<maxHistory>30</maxHistory></rollingPolicy>?<encoder>?<pattern>%-4relative?[%thread]?%-5level?%logger{35}?-?%msg%n</pattern>?</encoder>?</appender>?<root?level="DEBUG">?<appender-ref?ref="FILE"?/>?</root>? </configuration>3.2.2 文件大小策略
以文件大小為切分條件,<rollingPolicy>的class要設置為ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy,一個典型示例(活動日志文件大小超過30M則生成新的活動日志文件)如下:
<configuration>?<appender?name="FILE"?class="ch.qos.logback.core.rolling.RollingFileAppender">?<rollingPolicy?class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">?<fileNamePattern>logFile.%d{yyyy-MM-dd}.%i.log</fileNamePattern>??<maxFileSize>30MB</maxFileSize></rollingPolicy>?<encoder>?<pattern>%-4relative?[%thread]?%-5level?%logger{35}?-?%msg%n</pattern>?</encoder>?</appender>?<root?level="DEBUG">?<appender-ref?ref="FILE"?/>?</root>? </configuration>要注意的是,<fileNamePattern>中,%i必須要有,如果同一天產生多個歸檔日志文件,%i會產生一個后綴加以區分。例如mutest.2019-07-28.0.log?和?mutest.2019-07-28.1.log。
3.2.3 時間與文件大小策略
根據日志文件大小和時間周期作為切分條件,滿足其中任意一個就要做切分。<rollingPolicy>的class要設置為ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy,一個典型示例如下:
<configuration>?<appender?name="fileLog"?class="ch.qos.logback.core.rolling.RollingFileAppender"><file>mutest.log</file><encoder><pattern>%d?[%thread]?%-5level?-[%file:%line]-?%msg%n</pattern><charset>UTF-8</charset></encoder><rollingPolicy?class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>${logFile}.%d{yyyy-MM-dd}.%i.log</fileNamePattern><maxFileSize>${maxFileSize}</maxFileSize></rollingPolicy></appender><root?level="DEBUG">?<appender-ref?ref="FILE"?/>?</root>? </configuration>同樣,<fileNamePattern>中必須有%i。
3.3 日志過濾
首先,了解一下,日志級別從低到高分為:
TRACE?<?DEBUG?<?INFO?<?WARN?<?ERROR?<?FATAL有時候,我們需要對日志進行過濾,logback提供了多種過濾規則的實現。
3.3.1 LevelFilter
比如說,日志級別為info以上,但我們不想打印warn類型的日志,那么按照下面的配置做:
<filter?class="ch.qos.logback.classic.filter.LevelFilter"><level>warn</level><onMatch>DENY</onMatch><onMismatch>ACCEPT</onMismatch> </filter>幾個參數的含義:
ch.qos.logback.classic.filter.LevelFilter:過濾規則。這里是根據日志級別進行匹配。
level:要匹配的日志級別。
<onMatch>DENY</onMatch>:匹配到的日志會被拒絕。
<onMismatch>ACCEPT</onMismatch>:未匹配到的日志會被打印。
3.3.2 ThresholdFilter
除了?ch.qos.logback.classic.filter.LevelFilter外,還有一種過濾策略:ThresholdFilter。即臨界值過濾器,過濾掉低于指定臨界值的日志。當日志級別等于或高于臨界值時,過濾器返回NEUTRAL;當日志級別低于臨界值時,日志會被拒絕。
比如,設置只打印info級別以上的日志:
<filter?class="ch.qos.logback.classic.filter.ThresholdFilter"><level>info</level> </filter>3.3.3 EvaluatorFilter
EvaluatorFilter是求值過濾器,評估、鑒別日志是否符合指定條件。
<filter?class="ch.qos.logback.core.filter.EvaluatorFilter">?????????<evaluator>?<!--?默認為?ch.qos.logback.classic.boolex.JaninoEventEvaluator?-->???<expression>return?message.contains("success");</expression></evaluator>???<OnMatch>ACCEPT</OnMatch>??<OnMismatch>DENY</OnMismatch>?? </filter>???屬性釋義:
<evaluator>:鑒別器,常用的鑒別器是JaninoEventEvaluato,也是默認的鑒別器,它以任意的Java布爾值表達式作為求值條件,求值條件在配置文件解釋過成功被動態編譯,布爾值表達式返回true就表示符合過濾條件。evaluator有個子標簽<expression>,用于配置求值條件。
<onMatch>:用于配置符合過濾條件的操作,ACCEPT或DENY
<onMismatch>:用于配置不符合過濾條件的操作,ACCEPT或DENY
3.4 與配置文件結合
Spring Boot項目的配置文件有 application.properties 文件和 application.yml 文件兩種,而我個人比較喜歡用 yml 文件。
application.yml 文件中對日志的配置:
logging:config:?logback.xmllevel:com.example.demo.dao:?tracelogging.config 用來指定項目啟動的時候,讀取哪個配置文件,這里指定的日志配置文件是根路徑下的 logback.xml 文件。關于日志的相關配置信息,都放在了 logback.xml 文件中。
logging.level 用來指定具體的 Mapper 中日志的輸出級別,上面的配置表示 com.example.demo.dao 包下的所有 Mapper 日志輸出級別為 Trace,會將操作數據庫的 SQL 打印出來。開發時設置成 trace 方便定位問題,在生產環境上,將這個日志級別再設置成 error 級別即可。
常用的日志級別按照從高到低依次為:ERROR、WARN、INFO、DEBUG。
面試官問:前后端分離項目,有什么優缺點?我說:沒
2020 年騰訊新增 20 億行代碼,鵝廠第一編程語言還是它
通俗講解分布式鎖,看完不懂算我輸
寫博客能月入10K?
一款基于 Spring Boot 的現代化社區(論壇/問答/社交網絡/博客)
這或許是最美的Vue+Element開源后臺管理UI
推薦一款高顏值的 Spring Boot 快速開發框架
一款基于 Spring Boot 的現代化社區(論壇/問答/社交網絡/博客)
13K點贊都基于 Vue+Spring 前后端分離管理系統ELAdmin,大愛
想接私活時薪再翻一倍,建議根據這幾個開源的SpringBoot項目
總結
以上是生活随笔為你收集整理的SpringBoot 项目使用 SLF4J+logback 进行日志记录,来增强可维护性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java开发怎么达到年薪 50w ?我有
- 下一篇: Java中的 Switch 是如何支持