Log4j 介紹過了,SLF4J 也介紹過了绎秒,那接下來,你懂的厨喂,Logback 就要隆重地登場了,畢竟它哥仨有一個爹庄呈,那就是巨佬 Ceki Gulcu蜕煌。
就在昨天,老板聽我說完 Logback 有多牛逼之后诬留,徹底動心了斜纪,對我下了死命令,“這么好的日志系統(tǒng)文兑,你還不趕緊點盒刚,把它切換到咱的項目當(dāng)中!”
我們項目之前用的 Log4j绿贞,在我看來因块,已經(jīng)足夠用了,畢竟是小公司籍铁,性能上的要求沒那么苛刻贮聂。
01、Logback 強(qiáng)在哪
1)非常自然地實現(xiàn)了 SLF4J寨辩,不需要像 Log4j 和 JUL 那樣加一個適配層。
2)Spring Boot 的默認(rèn)日志框架使用的是 Logback歼冰。一旦某款工具庫成為了默認(rèn)選項靡狞,那就說明這款工具已經(jīng)超過了其他競品。
注意看下圖(證據(jù)找到了隔嫡,來自 Spring Boot 官網(wǎng)):
也可以通過源碼的形式看得到:
3)支持自動重新加載配置文件甸怕,不需要另外創(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 會自動導(dǎo)入另外兩個依賴:
logback-core 是 Logback 的核心,logback-classic 是 SLF4J 的實現(xiàn)荡含。
第二步咒唆,來個最簡單的測試用例:
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释液,所以如果項目是從 Log4j + SLF4J 切換到 Logback 的話全释,此時的代碼是零改動的。
運行 Test 類误债,可以在控制臺看到以下信息:
12:04:20.149 [main] DEBUG com.itwanger.Test - logback
在沒有配置文件的情況下浸船,一切都是默認(rèn)的妄迁,Logback 的日志信息會輸出到控制臺±蠲可以通過 StatusPrinter 來打印 Logback 的內(nèi)部信息:
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
StatusPrinter.print(lc);
在 main 方法中添加以上代碼后登淘,再次運行 Test 類,可以在控制臺看到以下信息:
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 會在 classpath 路徑下先尋找 logback-test.xml 文件形帮,沒有找到的話,尋找 logback.groovy 文件周叮,還沒有的話辩撑,尋找 logback.xml 文件,都找不到的話仿耽,就輸出到控制臺合冀。
一般來說,我們會在本地環(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)為 <configuration>
元素,包含 0 或多個 <appender>
元素奕删,其后跟 0 或多個 <logger>
元素俺泣,其后再跟最多只能存在一個的 <root>
元素。
1)配置 appender完残,也就是配置日志的輸出目的地伏钠,通過 name 屬性指定名字,通過 class 屬性指定目的地:
- ch.qos.logback.core.ConsoleAppender:輸出到控制臺谨设。
- ch.qos.logback.core.FileAppender:輸出到文件熟掂。
- ch.qos.logback.core.rolling.RollingFileAppender:文件大小超過閾值時產(chǎn)生一個新文件。
除了輸出到本地扎拣,還可以通過 SocketAppender 和 SSLSocketAppender 輸出到遠(yuǎn)程設(shè)備赴肚,通過 SMTPAppender 輸出到郵件。甚至可以通過 DBAppender 輸出到數(shù)據(jù)庫中二蓝。
encoder 負(fù)責(zé)把日志信息轉(zhuǎn)換成字節(jié)數(shù)組尊蚁,并且把字節(jié)數(shù)組寫到輸出流。
pattern 用來指定日志的輸出格式:
-
%d
:輸出的時間格式侣夷。 -
%thread
:日志的線程名横朋。 -
%-5level
:日志的輸出級別,填充到 5 個字符百拓。比如說 info 只有 4 個字符琴锭,就填充一個空格晰甚,這樣日志信息就對齊了。
反例(沒有指定 -5 的情況):
-
%logger{length}
:logger 的名稱决帖,length 用來縮短名稱厕九。沒有指定表示完整輸出;0 表示只輸出 logger 最右邊點號之后的字符串地回;其他數(shù)字表示輸出小數(shù)點最后邊點號之前的字符數(shù)量扁远。 -
%msg
:日志的具體信息。 -
%n
:換行符刻像。 -
%relative
:輸出從程序啟動到創(chuàng)建日志記錄的時間畅买,單位為毫秒。
2)配置 root细睡,它只支持一個屬性——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)信息求妹。
重新運行 Test 類,可以在控制臺看到以下信息:
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)自動重載配置佳窑。
之前提到 Logback 很強(qiáng)的一個功能就是支持自動重載配置制恍,那想要啟用這個功能也非常簡單,只需要在 configuration 元素上添加 scan=true
即可神凑。
<configuration scan="true">
...
</configuration>
默認(rèn)情況下净神,掃描的時間間隔是一分鐘一次。如果想要調(diào)整時間間隔溉委,可以通過 scanPeriod 屬性進(jìn)行調(diào)整鹃唯,單位可以是毫秒(milliseconds)、秒(seconds)瓣喊、分鐘(minutes)或者小時(hours)坡慌。
下面這個示例指定的時間間隔是 30 秒:
<configuration scan="true" scanPeriod="30 seconds"
...
</configuration>
注意:如果指定了時間間隔,沒有指定時間單位藻三,默認(rèn)的時間單位為毫秒洪橘。
當(dāng)設(shè)置 scan=true
后跪者,Logback 會起一個 ReconfigureOnChangeTask 的任務(wù)來監(jiān)視配置文件的變化。
03熄求、把 log4j.properties 轉(zhuǎn)成 logback-test.xml
如果你的項目以前用的 Log4j渣玲,那么可以通過下面這個網(wǎng)址把 log4j.properties 轉(zhuǎn)成 logback-test.xml:
把之前 log4j.properties 的內(nèi)容拷貝一份:
### 設(shè)置###
log4j.rootLogger = debug,stdout,D,E
### 輸出信息到控制臺 ###
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 級別以上的日志到=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 級別以上的日志到=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 ] %m%n
粘貼到該網(wǎng)址的文本域:
點擊「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)三個 appender 都在忘衍。
但是呢,轉(zhuǎn)換后的文件并不能直接使用卿城,需要稍微做一些調(diào)整枚钓,因為:
第一,日志的格式化有細(xì)微的不同藻雪,Logback 中沒有 %l
秘噪。
第二,RollingFileAppender 需要指定 RollingPolicy 和 TriggeringPolicy勉耀,前者負(fù)責(zé)日志的滾動功能指煎,后者負(fù)責(zé)日志滾動的時機(jī)。如果 RollingPolicy 也實現(xiàn)了 TriggeringPolicy 接口便斥,那么只需要設(shè)置 RollingPolicy 就好了至壤。
TimeBasedRollingPolicy 和 SizeAndTimeBasedRollingPolicy 是兩種最常用的滾動策略。
TimeBasedRollingPolicy 同時實現(xiàn)了 RollingPolicy 與 TriggeringPolicy 接口枢纠,因此使用 TimeBasedRollingPolicy 的時候就可以不指定 TriggeringPolicy像街。
TimeBasedRollingPolicy 可以指定以下屬性:
fileNamePattern,用來定義文件的名字(必選項)晋渺。它的值應(yīng)該由文件名加上一個
%d
的占位符镰绎。%d
應(yīng)該包含java.text.SimpleDateFormat
中規(guī)定的日期格式,缺省是yyyy-MM-dd
木西。滾動周期是通過 fileNamePattern 推斷出來的畴栖。maxHistory,最多保留多少數(shù)量的日志文件(可選項)八千,將會通過異步的方式刪除舊的文件吗讶。比如,你指定按月滾動恋捆,指定
maxHistory = 6
照皆,那么 6 個月內(nèi)的日志文件將會保留,超過 6 個月的將會被刪除沸停。totalSizeCap膜毁,所有日志文件的大小(可選項)。超出這個大小時爽茴,舊的日志文件將會被異步刪除葬凳。需要配合 maxHistory 屬性一起使用,并且是第二條件室奏。
來看下面這個 RollingFileAppender 配置:
<appender name="D" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天滾動 -->
<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>
基于按天滾動的文件策略,最多保留 30 天胧沫,最大大小為 30G昌简。
SizeAndTimeBasedRollingPolicy 比 TimeBasedRollingPolicy 多了一個日志文件大小設(shè)定的屬性:maxFileSize,其他完全一樣绒怨。
基于我們對 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");
}
}
運行后犬金,可以在 target 目錄下看到兩個文件:debug.log 和 errror.log。
到此為止六剥,項目已經(jīng)從 Log4j 切換到 Logback 了晚顷,過程非常的絲滑順暢,嘿嘿疗疟。
04该默、Logback 手冊
Logback 的官網(wǎng)上是有一份手冊的,非常詳細(xì)策彤,足足 200 多頁栓袖,只不過是英文版的。小伙伴們可以看完我這篇文章入門實操的 Logback 教程后店诗,到下面的地址看官方手冊裹刮。
如果英文閱讀能力有限的話,可以到 GitHub 上查看雷鋒翻譯的中文版:
當(dāng)然了庞瘸,還有一部分小伙伴喜歡看離線版的 PDF捧弃,我已經(jīng)整理好了:
實話實話吧,白嫖的感覺就是舒服恕洲,趕緊去下載吧塔橡!日常求個三連梅割,謝謝你勤勞的手指霜第,嘿嘿。