老板下了死命令,要把日志系統(tǒng)切換到Logback
Log4j 介紹過了,SLF4J 也介紹過了,那接下來,你懂的,Logback 就要隆重地登場(chǎng)了,畢竟它哥仨有一個(gè)爹,那就是巨佬 Ceki Gulcu。
就在昨天,老板聽我說完 Logback 有多牛逼之后,徹底動(dòng)心了,對(duì)我下了死命令,“這么好的日志系統(tǒng),你還不趕緊點(diǎn),把它切換到咱的項(xiàng)目當(dāng)中!”
我們項(xiàng)目之前用的 Log4j,在我看來,已經(jīng)足夠用了,畢竟是小公司,性能上的要求沒那么苛刻。
01、Logback 強(qiáng)在哪
1)非常自然地實(shí)現(xiàn)了 SLF4J,不需要像 Log4j 和 JUL 那樣加一個(gè)適配層。
2)Spring Boot 的默認(rèn)日志框架使用的是 Logback。一旦某款工具庫(kù)成為了默認(rèn)選項(xiàng),那就說明這款工具已經(jīng)超過了其他競(jìng)品。
注意看下圖(證據(jù)找到了,來自 Spring Boot 官網(wǎng)):
也可以通過源碼的形式看得到:
3)支持自動(dòng)重新加載配置文件,不需要另外創(chuàng)建掃描線程來監(jiān)視。
4)既然是巨佬的新作,那必然在性能上有了很大的提升,不然呢?
02、Logback 使用示例
第一步,在 pom.xml 文件中添加 Logback 的依賴:
- <dependency>
- <groupId>ch.qos.logback</groupId>
- <artifactId>logback-classic</artifactId>
- <version>1.2.3</version>
- </dependency>
Maven 會(huì)自動(dòng)導(dǎo)入另外兩個(gè)依賴:
logback-core 是 Logback 的核心,logback-classic 是 SLF4J 的實(shí)現(xiàn)。
第二步,來個(gè)最簡(jiǎn)單的測(cè)試用例:
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- /**
- * @author 微信搜「沉默王二」,回復(fù)關(guān)鍵字 PDF
- */
- public class Test {
- static Logger logger = LoggerFactory.getLogger(Test.class);
- public static void main(String[] args) {
- logger.debug("logback");
- }
- }
Logger 和 LoggerFactory 都來自 SLF4J,所以如果項(xiàng)目是從 Log4j + SLF4J 切換到 Logback 的話,此時(shí)的代碼是零改動(dòng)的。
運(yùn)行 Test 類,可以在控制臺(tái)看到以下信息:
- 12:04:20.149 [main] DEBUG com.itwanger.Test - logback
在沒有配置文件的情況下,一切都是默認(rèn)的,Logback 的日志信息會(huì)輸出到控制臺(tái)??梢酝ㄟ^ StatusPrinter 來打印 Logback 的內(nèi)部信息:
- LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
- StatusPrinter.print(lc);
在 main 方法中添加以上代碼后,再次運(yùn)行 Test 類,可以在控制臺(tái)看到以下信息:
- 12:59:22.314 [main] DEBUG com.itwanger.Test - logback
- 12:59:22,261 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.xml]
- 12:59:22,262 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.groovy]
- 12:59:22,262 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.xml]
- 12:59:22,268 |-INFO in ch.qos.logback.classic.BasicConfigurator@5e853265 - Setting up default configuration.
也就是說,Logback 會(huì)在 classpath 路徑下先尋找 logback-test.xml 文件,沒有找到的話,尋找 logback.groovy 文件,還沒有的話,尋找 logback.xml 文件,都找不到的話,就輸出到控制臺(tái)。
一般來說,我們會(huì)在本地環(huán)境中配置 logback-test.xml,在生產(chǎn)環(huán)境下配置 logback.xml。
**第三步,**在 resource 目錄下增加 logback-test.xml 文件,內(nèi)容如下所示:
- <configuration debug="true">
- <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
- <encoder>
- <pattern>%d{HH:mm:ss.SSS} %relative [%thread] %-5level %logger{36} - %msg%n</pattern>
- </encoder>
- </appender>
- <root level="debug">
- <appender-ref ref="STDOUT" />
- </root>
- </configuration>
Logback 的配置文件非常靈活,最基本的結(jié)構(gòu)為
1)配置 appender,也就是配置日志的輸出目的地,通過 name 屬性指定名字,通過 class 屬性指定目的地:
- ch.qos.logback.core.ConsoleAppender:輸出到控制臺(tái)。
- ch.qos.logback.core.FileAppender:輸出到文件。
- ch.qos.logback.core.rolling.RollingFileAppender:文件大小超過閾值時(shí)產(chǎn)生一個(gè)新文件。
除了輸出到本地,還可以通過 SocketAppender 和 SSLSocketAppender 輸出到遠(yuǎn)程設(shè)備,通過 SMTPAppender 輸出到郵件。甚至可以通過 DBAppender 輸出到數(shù)據(jù)庫(kù)中。
encoder 負(fù)責(zé)把日志信息轉(zhuǎn)換成字節(jié)數(shù)組,并且把字節(jié)數(shù)組寫到輸出流。
pattern 用來指定日志的輸出格式:
- %d:輸出的時(shí)間格式。
- %thread:日志的線程名。
- %-5level:日志的輸出級(jí)別,填充到 5 個(gè)字符。比如說 info 只有 4 個(gè)字符,就填充一個(gè)空格,這樣日志信息就對(duì)齊了。
反例(沒有指定 -5 的情況):
- %logger{length}:logger 的名稱,length 用來縮短名稱。沒有指定表示完整輸出;0 表示只輸出 logger 最右邊點(diǎn)號(hào)之后的字符串;其他數(shù)字表示輸出小數(shù)點(diǎn)最后邊點(diǎn)號(hào)之前的字符數(shù)量。
- %msg:日志的具體信息。
- %n:換行符。
- %relative:輸出從程序啟動(dòng)到創(chuàng)建日志記錄的時(shí)間,單位為毫秒。
2)配置 root,它只支持一個(gè)屬性——level,值可以為:TRACE、DEBUG、INFO、WARN、ERROR、ALL、OFF。
appender-ref 用來指定具體的 appender。
3)查看內(nèi)部狀態(tài)信息。
可以在代碼中通過 StatusPrinter 來打印 Logback 內(nèi)部狀態(tài)信息,也可以通過在 configuration 上開啟 debug 來打印內(nèi)部狀態(tài)信息。
重新運(yùn)行 Test 類,可以在控制臺(tái)看到以下信息:
- 13:54:54,718 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback-test.xml] at [file:/Users/maweiqing/Documents/GitHub/JavaPointNew/codes/logbackDemo/target/classes/logback-test.xml]
- 13:54:54,826 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
- 13:54:54,828 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
- 13:54:54,833 |-INFO in ch.qos.logback.core.joran.action.NestedComplexPropertyIA - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
- 13:54:54,850 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - Setting level of ROOT logger to DEBUG
- 13:54:54,850 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[ROOT]
- 13:54:54,850 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - End of configuration.
- 13:54:54,851 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@f8c1ddd - Registering current configuration as safe fallback point
- 13:54:54.853 [main] DEBUG com.itwanger.Test - logback
4)自動(dòng)重載配置。
之前提到 Logback 很強(qiáng)的一個(gè)功能就是支持自動(dòng)重載配置,那想要啟用這個(gè)功能也非常簡(jiǎn)單,只需要在 configuration 元素上添加 scan=true 即可。
- <configuration scan="true">
- ...
- </configuration>
默認(rèn)情況下,掃描的時(shí)間間隔是一分鐘一次。如果想要調(diào)整時(shí)間間隔,可以通過 scanPeriod 屬性進(jìn)行調(diào)整,單位可以是毫秒(milliseconds)、秒(seconds)、分鐘(minutes)或者小時(shí)(hours)。
下面這個(gè)示例指定的時(shí)間間隔是 30 秒:
- <configuration scan="true" scanPeriod="30 seconds"
- ...
- </configuration>
注意:如果指定了時(shí)間間隔,沒有指定時(shí)間單位,默認(rèn)的時(shí)間單位為毫秒。
當(dāng)設(shè)置 scan=true 后,Logback 會(huì)起一個(gè) ReconfigureOnChangeTask 的任務(wù)來監(jiān)視配置文件的變化。
03、把 log4j.properties 轉(zhuǎn)成 logback-test.xml
如果你的項(xiàng)目以前用的 Log4j,那么可以通過下面這個(gè)網(wǎng)址把 log4j.properties 轉(zhuǎn)成 logback-test.xml:
http://logback.qos.ch/translator/
把之前 log4j.properties 的內(nèi)容拷貝一份:
- ### 設(shè)置###
- log4j.rootLogger = debug,stdout,D,E
- ### 輸出信息到控制臺(tái) ###
- log4j.appender.stdout = org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.Target = System.out
- log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
- ### 輸出DEBUG 級(jí)別以上的日志到=debug.log ###
- log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
- log4j.appender.D.File = debug.log
- log4j.appender.D.Append = true
- log4j.appender.D.Threshold = DEBUG
- log4j.appender.D.layout = org.apache.log4j.PatternLayout
- log4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
- ### 輸出ERROR 級(jí)別以上的日志到=error.log ###
- log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
- log4j.appender.E.File =error.log
- log4j.appender.E.Append = true
- log4j.appender.E.Threshold = ERROR
- log4j.appender.E.layout = org.apache.log4j.PatternLayout
- log4j.appender.E.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %
粘貼到該網(wǎng)址的文本域:
點(diǎn)擊「Translate」,可以得到以下內(nèi)容:
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- For assistance related to logback-translator or configuration -->
- <!-- files in general, please contact the logback user mailing list -->
- <!-- at http://www.qos.ch/mailman/listinfo/logback-user -->
- <!-- -->
- <!-- For professional support please see -->
- <!-- http://www.qos.ch/shop/products/professionalSupport -->
- <!-- -->
- <configuration>
- <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
- <Target>System.out</Target>
- <encoder>
- <pattern>[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n</pattern>
- </encoder>
- </appender>
- <appender name="D" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <!--See http://logback.qos.ch/manual/appenders.html#RollingFileAppender-->
- <!--and http://logback.qos.ch/manual/appenders.html#TimeBasedRollingPolicy-->
- <!--for further documentation-->
- <Append>true</Append>
- <File>debug.log</File>
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
- <level>DEBUG</level>
- </filter>
- </appender>
- <appender name="E" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <!--See http://logback.qos.ch/manual/appenders.html#RollingFileAppender-->
- <!--and http://logback.qos.ch/manual/appenders.html#TimeBasedRollingPolicy-->
- <!--for further documentation-->
- <File>error.log</File>
- <Append>true</Append>
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
- <level>ERROR</level>
- </filter>
- </appender>
- <root level="debug">
- <appender-ref ref="stdout"/>
- <appender-ref ref="D"/>
- <appender-ref ref="E"/>
- </root>
- </configuration>
可以確認(rèn)一下內(nèi)容,發(fā)現(xiàn)三個(gè) appender 都在。
但是呢,轉(zhuǎn)換后的文件并不能直接使用,需要稍微做一些調(diào)整,因?yàn)椋?/p>
第一,日志的格式化有細(xì)微的不同,Logback 中沒有 %l。
第二,RollingFileAppender 需要指定 RollingPolicy 和 TriggeringPolicy,前者負(fù)責(zé)日志的滾動(dòng)功能,后者負(fù)責(zé)日志滾動(dòng)的時(shí)機(jī)。如果 RollingPolicy 也實(shí)現(xiàn)了 TriggeringPolicy 接口,那么只需要設(shè)置 RollingPolicy 就好了。
TimeBasedRollingPolicy 和 SizeAndTimeBasedRollingPolicy 是兩種最常用的滾動(dòng)策略。
TimeBasedRollingPolicy 同時(shí)實(shí)現(xiàn)了 RollingPolicy 與 TriggeringPolicy 接口,因此使用 TimeBasedRollingPolicy 的時(shí)候就可以不指定 TriggeringPolicy。
TimeBasedRollingPolicy 可以指定以下屬性:
- fileNamePattern,用來定義文件的名字(必選項(xiàng))。它的值應(yīng)該由文件名加上一個(gè) %d 的占位符。%d 應(yīng)該包含 java.text.SimpleDateFormat 中規(guī)定的日期格式,缺省是 yyyy-MM-dd。滾動(dòng)周期是通過 fileNamePattern 推斷出來的。
- maxHistory,最多保留多少數(shù)量的日志文件(可選項(xiàng)),將會(huì)通過異步的方式刪除舊的文件。比如,你指定按月滾動(dòng),指定 maxHistory = 6,那么 6 個(gè)月內(nèi)的日志文件將會(huì)保留,超過 6 個(gè)月的將會(huì)被刪除。
- totalSizeCap,所有日志文件的大小(可選項(xiàng))。超出這個(gè)大小時(shí),舊的日志文件將會(huì)被異步刪除。需要配合 maxHistory 屬性一起使用,并且是第二條件。
來看下面這個(gè) RollingFileAppender 配置:
- <appender name="D" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <file>debug.log</file>
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 按天滾動(dòng) -->
- <fileNamePattern>debug.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 保存 30 天的歷史記錄,最大大小為 30GB -->
- <maxHistory>30</maxHistory>
- <totalSizeCap>3GB</totalSizeCap>
- </rollingPolicy>
- <encoder>
- <pattern>%relative [%thread] %level %logger{35} - %msg%n</pattern>
- </encoder>
- </appender>
基于按天滾動(dòng)的文件策略,最多保留 30 天,最大大小為 30G。
SizeAndTimeBasedRollingPolicy 比 TimeBasedRollingPolicy 多了一個(gè)日志文件大小設(shè)定的屬性:maxFileSize,其他完全一樣。
基于我們對(duì) RollingPolicy 的了解,可以把 logback-test.xml 的內(nèi)容調(diào)整為以下內(nèi)容:
- <configuration>
- <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
- <Target>System.out</Target>
- <encoder>
- <pattern>%d{HH:mm:ss.SSS} [%thread] %level %logger{36} - %msg%n</pattern>
- </encoder>
- </appender>
- <appender name="D" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <Append>true</Append>
- <File>debug.log</File>
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 按天輪轉(zhuǎn) -->
- <fileNamePattern>debug.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 保存 30 天的歷史記錄,最大大小為 30GB -->
- <maxHistory>30</maxHistory>
- <totalSizeCap>3GB</totalSizeCap>
- </rollingPolicy>
- <encoder>
- <pattern>%relative [%thread] %-5level %logger{35} - %msg%n</pattern>
- </encoder>
- </appender>
- <appender name="E" class="ch.qos.logback.core.rolling.RollingFileAppender">
- <File>error.log</File>
- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
- <!-- 按天輪轉(zhuǎn) -->
- <fileNamePattern>error.%d{yyyy-MM-dd}.log</fileNamePattern>
- <!-- 保存 30 天的歷史記錄,最大大小為 30GB -->
- <maxHistory>30</maxHistory>
- <totalSizeCap>3GB</totalSizeCap>
- </rollingPolicy>
- <encoder>
- <pattern>%d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n</pattern>
- </encoder>
- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
- <level>ERROR</level>
- </filter>
- </appender>
- <root level="debug">
- <appender-ref ref="stdout"/>
- <appender-ref ref="D"/>
- <appender-ref ref="E"/>
- </root>
- </configuration>
修改 Test 類的內(nèi)容:
- public class Test {
- static Logger logger = LoggerFactory.getLogger(Test.class);
- public static void main(String[] args) {
- logger.debug("logback");
- logger.error("logback");
- }
- }
運(yùn)行后,可以在 target 目錄下看到兩個(gè)文件:debug.log 和 errror.log。
到此為止,項(xiàng)目已經(jīng)從 Log4j 切換到 Logback 了,過程非常的絲滑順暢,嘿嘿。
04、Logback 手冊(cè)
Logback 的官網(wǎng)上是有一份手冊(cè)的,非常詳細(xì),足足 200 多頁(yè),只不過是英文版的。小伙伴們可以看完我這篇文章入門實(shí)操的 Logback 教程后,到下面的地址看官方手冊(cè)。
http://logback.qos.ch/manual/index.html
如果英文閱讀能力有限的話,可以到 GitHub 上查看雷鋒翻譯的中文版:
https://github.com/itwanger/logback-chinese-manual
當(dāng)然了,還有一部分小伙伴喜歡看離線版的 PDF,我已經(jīng)整理好了:
鏈接:https://pan.baidu.com/s/16FrbwycYUUIfKknlLhRKYA 密碼:bptl
實(shí)話實(shí)話吧,白嫖的感覺就是舒服,趕緊去下載吧!
本文轉(zhuǎn)載自微信公眾號(hào)「沉默王二」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系沉默王二公眾號(hào)。