這篇文章給大家介紹springboot項目使用日志工具Logback把日志輸出到控制臺拍屑,輸出到文件的具體方法凿跳;介紹了Logback的xml配置文件中各個標(biāo)簽的具體內(nèi)容件豌;列出了常見的配置文件內(nèi)容。
Logback簡介:Logback是一個開源的日志組件控嗜,師出同門,與log4j一樣曾掂,logback也是由Ceki Gülcü開發(fā)的開源日志組件壁顶,可以說是log4j的改進(jìn)版;在現(xiàn)如今的項目中若专,logback的出現(xiàn)次數(shù)越來越多,是目前主流首選的日志記錄工具膊爪。
logback分成三個模塊:logback-core嚎莉,logback- classic,logback-access(這個不常用)萝喘。
1.Logback日志組件各個模塊的功能
- logback-core:提供了LogBack的核心功能琼懊,是另外兩個組件的基礎(chǔ)。
- logback-classic:實現(xiàn)了Slf4j的API启妹,所以當(dāng)想配合Slf4j使用時醉旦,需要引入logback-classic。
什么是Slf4j:簡單日志門面(Simple Logging Facade for Java)檬输,不是具體的日志解決方案匈棘,它只服務(wù)于各種各樣的日志系統(tǒng)。在使用SLF4J的時候,不需要在代碼中或配置文件中指定你打算使用那個具體的日志系統(tǒng)鹃愤。
- logback-access:為了集成Servlet環(huán)境而準(zhǔn)備的完域,可提供HTTP-access的日志接口。
2.Logback日志組件各個模塊的maven依賴
<!-- logback -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>${logback.version}</version>
</dependency>
3.項目啟動時Logback日志配置文件掃描規(guī)則
啟動項目時凹耙,logback會按照如下順序掃描配置文件:
- 在系統(tǒng)配置文件System Properties中尋找是否有l(wèi)ogback.configurationFile對應(yīng)的value
- 在classpath下尋找是否有l(wèi)ogback.groovy(即logback支持groovy與xml兩種配置方式)
- 在classpath下尋找是否有l(wèi)ogback-test.xml
- 在classpath下尋找是否有l(wèi)ogback.xml
以上任何一項找到了乌妙,就不進(jìn)行后續(xù)掃描,按照對應(yīng)的配置進(jìn)行l(wèi)ogback的初始化虐沥,可從控制臺輸出信息中查看加載的配置文件泽艘。
當(dāng)所有以上四項都找不到的情況下,logback會調(diào)用ch.qos.logback.classic.BasicConfigurator的configure方法匹涮,構(gòu)造一個ConsoleAppender用于向控制臺輸出日志,默認(rèn)日志輸出格式為%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n喜每。
在Springboot項目中可以自定義logback配置文件名及文件位置
要想讓Springboot項目識別到該logback配置文件雳攘,只需要在Springboot配置文件中定義好配置文件的加載路徑即可如下所示:
4.Logback具體可實現(xiàn)的功能
- 自動重新加載配置文件
當(dāng)配置文件修改了,Logback-classic能自動重新加載配置文件刚照。掃描過程快且安全喧兄,它并不需要另外創(chuàng)建一個掃描線程。 - 自動去除舊的日志文件
通過設(shè)置TimeBasedRollingPolicy或者SizeAndTimeBasedFNATP的maxHistory屬性吠冤,你可以控制已經(jīng)產(chǎn)生日志文件的最大數(shù)量。如果設(shè)置maxHistory 12闸昨,那那些log文件超過12個月的都會被自動移除。 - 堆棧樹帶有包版本
Logback在打出堆棧樹日志時饵较,會帶上包的數(shù)據(jù)循诉。 - 自動壓縮已經(jīng)打出來的log
RollingFileAppender在產(chǎn)生新文件的時候,會自動壓縮已經(jīng)打出來的日志文件茄猫。壓縮是個異步過程,所以甚至對于大的日志文件脆侮,在壓縮過程中應(yīng)用不會受任何影響勇劣。
5.Logback配置文件詳解
- 根節(jié)點(diǎn)<configuration>
<!-- 輸出logback內(nèi)部日志信息,每隔30s判斷一下配置文件有沒有更新比默,若更新,則重新加載 -->
<configuration scan="true" scanPeriod="30 seconds" debug="true">
<!--
scan: 當(dāng)此屬性設(shè)置為true時篡九,配置文件如果發(fā)生改變醋奠,將會被重新加載,默認(rèn)值為true沛善。
scanPeriod: 設(shè)置監(jiān)測配置文件是否有修改的時間間隔例证,如果沒有給出時間單位迷捧,默認(rèn)單位是毫秒。當(dāng)scan為true時漠秋,此屬性生效。默認(rèn)的時間間隔為1分鐘捅位。
debug: 當(dāng)此屬性設(shè)置為true時,將打印出logback內(nèi)部日志信息尿扯,實時查看logback運(yùn)行狀態(tài)焰雕。默認(rèn)值為false。
-->
- 設(shè)置變量<property>
<configuration>
<!-- 定義日志文件的存儲地址 -->
<property name="LOG_HOME" value="log"/>
<!--格式化輸出:%d表示日期矩屁,%thread表示線程名,%-5level:級別從左顯示5個字符寬度 %msg:日志消息泊脐,%n是換行符-->
<property name="LOG_PATTERN" value="%d{yyyyMMdd:HH:mm:ss.SSS} [%thread] %-5level %msg%n"/>
</configuration>
<!--
name:變量的名稱烁峭,可以隨意起名,但建議名字要簡明直譯耘柱;
value:變量的值棍现;
在配置文件中,我們可以用 ${} 的方式來使用己肮,將變量引入到其他節(jié)點(diǎn)中去。
-->
- <appender>
負(fù)責(zé)寫日志的組件娄柳,有兩個必要屬性name和class
- 常用的控制臺輸出:ConsoleAppender
<!-- name指定<appender>的名稱
class指定<appender>的全限定名 -->
<!-- 控制臺輸出 appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- <encoder>表示輸出格式 -->
<pattern>${LOG_PATTERN}</pattern>
<!-- 控制臺也要使用UTF-8艘绍,不要使用GBK,否則會中文亂碼 -->
<charset>utf8</charset>
</encoder>
</appender>
- 常用的滾動記錄文件:RollingFileAppender
<!-- INFO日志 appender: 按照每天生成日志文件 -->
<appender name="INFO-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 過濾器挎挖,只記錄 info 級別以上的日志 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<!-- 寫入的日志文件名航夺,可以使相對目錄也可以是絕對目錄,如果上級目錄不存在則自動創(chuàng)建 -->
<file>${LOG_HOME}/iot-sdk-info.log</file>
<!-- 如果為true表示日志被追加到文件結(jié)尾阳掐,如果是false表示清空文件 -->
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件輸出的文件名:
%d:可以包含一個Java.text.SimpleDateFormat指定的時間格式
%i:自增數(shù)字
-->
<fileNamePattern>${LOG_HOME}/iot-sdk-info.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
<!-- 日志文件保存歷史數(shù)量:控制保留的歸檔文件的最大數(shù)量,如果超出數(shù)量就刪除舊文件 -->
<maxHistory>30</maxHistory>
<!-- 文件大小超過100MB歸檔 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
4.<encoder>
encoder節(jié)點(diǎn)負(fù)責(zé)兩件事情:
- 把日志信息轉(zhuǎn)換為字節(jié)數(shù)組
- 把字節(jié)數(shù)組寫到輸出流
以下是一個常用配置:
<!-- 控制臺輸出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 用來設(shè)置日志的輸入格式蝙茶,使用“%+轉(zhuǎn)換符”的方式蛉拙,如果要輸出”%”則必須使用”\”進(jìn)行轉(zhuǎn)義。-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 格式化輸出:https://logback.qos.ch/manual/layouts.html
%d 表示日期孕锄,
%thread 表示線程名,
%level 日志級別從左顯示5個字符寬度宦芦,
%t 線程名
%file:%line 文件名+行號轴脐,
%m 日志消息,%n是換行符
%X{traceId}:自定義設(shè)置的參數(shù)恬涧,后面會說碴巾。
-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %t %file:%line %X{traceId} -| %m%n</pattern>
<charset>utf8</charset>
</encoder>
</appender>
5.<filter>
配合appender使用,<filter>是<appender>的一個子節(jié)點(diǎn)厦瓢,表示在當(dāng)前給到的日志級別下再進(jìn)行一次過濾
- Level 級別過濾器
根據(jù)日志級別進(jìn)行過濾煮仇。如果日志級別等于配置級別,過濾器會根據(jù)onMath和onMismatch接收(ACCEPT)或拒絕(DENY)日志浙垫。
<!-- 控制臺輸出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 只記錄error級別的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
- ThresholdFilter: 臨界值過濾器
將日志級別低于<level>的全部進(jìn)行過濾。當(dāng)日志級別等于或高于臨界值時杉武,過濾器返回NEUTRAL佃声;當(dāng)日志級別低于臨界值時倘要,日志會被拒絕圾亏。
<!-- 控制臺輸出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 記錄info級別以上的日志 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
- <logger>與<root>
<logger>用來設(shè)置某一個包或者具體某一個類的日志打印級別、以及指定appender志鹃。
<logger>可以包含零個或者多個<appender-ref>元素,標(biāo)識這個appender將會添加到這個logger曹铃。
<root>也是<logger>元素,但它是根logger秘血,只有一個level屬性评甜,因為它的name就是ROOT
<!-- name:必填灰粮,指定受此logger約束的某一個包或者具體的某一個類忍坷。這個name表示的是LoggerFactory.getLogger(XXX.class),XXX的包路徑柑肴,包路徑越少越是父級
level:用來設(shè)置打印級別旬薯,五個常用打印級別從低至高依次為TRACE、DEBUG些侍、INFO、WARN岗宣、ERROR淋样,如果未設(shè)置此級別,那么當(dāng)前l(fā)ogger會繼承上級的級別
additivity:是否向上級logger傳遞打印信息刊咳,默認(rèn)為true -->
<logger name="com.example.iot" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-APPENDER"/>
<appender-ref ref="ERROR-APPENDER"/>
</logger>
<!-- 沒有配置<appender-ref>儡司,表示此<logger>不會打印出任何信息 -->
<logger name="com.example.iot.demo1" level="DEBUG" additivity="true" />
<!-- 沒有配置level,即繼承父級的level跷坝,<logger>的父級為<root>,那么level=info -->
<logger name="com.example.iot.demo2" additivity="false" />
<!-- 控制臺輸出日志級別 -->
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
6.Logback日志常用配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds" debug="true">
<!-- logback的根節(jié)點(diǎn) <configuration>的屬性scan淮韭、scanPeriod贴届、debug
scan: 當(dāng)此屬性設(shè)置為true時,配置文件如果發(fā)生改變毫蚓,將會被重新加載元潘,默認(rèn)值為true。
scanPeriod: 設(shè)置監(jiān)測配置文件是否有修改的時間間隔柬批,如果沒有給出時間單位,默認(rèn)單位是毫秒嗅虏。當(dāng)scan為true時上沐,此屬性生效。默認(rèn)的時間間隔為1分鐘龄广。
debug: 當(dāng)此屬性設(shè)置為true時蕴侧,將打印出logback內(nèi)部日志信息,實時查看logback運(yùn)行狀態(tài)敲才。默認(rèn)值為false择葡。
-->
<!-- 定義日志文件的存儲地址 -->
<property name="LOG_HOME" value="log"/>
<!-- 格式化輸出:
%d 表示日期,
%thread 表示線程名敏储,
%level 日志級別從左顯示5個字符寬度已添,
%thread 線程名
%file:%line 文件名:行號番舆,
%m 日志消息矾踱,
%n 換行符疏哗,
%X{traceId} 自定義設(shè)置的參數(shù)
%mdc 自定義參數(shù)
-->
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%5level) -- [%15.15t] %cyan(%-23.23logger{23}) : %m%n"/>
<!-- appender是configuration的子節(jié)點(diǎn),是負(fù)責(zé)寫日志的組件 -->
<!-- 控制臺輸出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<!-- 控制臺也要使用UTF-8贝搁,不要使用GBK芽偏,否則會中文亂碼 -->
<charset>utf8</charset>
</encoder>
</appender>
<!-- INFO日志 appender: 按照每天生成日志文件 -->
<appender name="INFO-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 過濾器,記錄info級別以上的日志 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<!-- 寫入的日志文件名膀哲,可以使相對目錄也可以是絕對目錄被碗,如果上級目錄不存在則自動創(chuàng)建 -->
<file>${LOG_HOME}/iot-sdk-info.log</file>
<!-- 如果為true表示日志被追加到文件結(jié)尾,如果是false表示清空文件 -->
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件輸出的文件名: %d可以包含一個Java.text.SimpleDateFormat指定的時間格式 -->
<fileNamePattern>${LOG_HOME}/iot-sdk-info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 日志文件保存歷史數(shù)量:控制保留的歸檔文件的最大數(shù)量兴喂,如果超出數(shù)量就刪除舊文件 -->
<maxHistory>30</maxHistory>
<!-- 文件大小超過100MB歸檔 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- 錯誤日志 appender: 按照每天生成日志文件 -->
<appender name="ERROR-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 過濾器焚志,只記錄error級別的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- 日志名稱 -->
<file>${LOG_HOME}/iot-sdk-error.log</file>
<append>true</append>
<!-- 每天生成一個日志文件酱酬,保存30天的日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件輸出的文件名:按天回滾 daily -->
<fileNamePattern>${LOG_HOME}/iot-sdk-error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 日志文件保留天數(shù) -->
<maxHistory>30</maxHistory>
<!-- 文件大小超過100MB歸檔 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- 指定項目中某個包,當(dāng)有日志操作行為時的日志記錄級別
級別依次為【從高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE
additivity=false 表示匹配之后佃迄,不再繼續(xù)傳遞給其他的logger
-->
<logger name="com.example.iot" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-APPENDER"/>
<appender-ref ref="ERROR-APPENDER"/>
</logger>
<!-- 控制臺輸出日志級別 -->
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
7.Logback高級特性異步輸出日志
之前的日志配置方式是基于同步的贵少,每次日志輸出到文件都會進(jìn)行一次磁盤IO。采用異步寫日志的方式而不讓此次寫日志發(fā)生磁盤IO普碎,阻塞線程從而造成不必要的性能損耗录平。異步輸出日志的方式很簡單缀皱,添加一個基于異步寫日志的appender动猬,并指向原先配置的appender即可。
logback AsyncAppender 目前在logback 1.0.11及以上版本存在
示例:
<!-- 異步輸出 -->
<appender name="ASYNC-INFO-APPENDER" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丟失日志.默認(rèn)的,如果隊列的80%已滿,則會丟棄TRACT钮莲、DEBUG彼水、INFO級別的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默認(rèn)的隊列的深度,該值會影響性能.默認(rèn)值為256 -->
<queueSize>256</queueSize>
<!-- 添加附加的appender,最多只能添加一個 -->
<appender-ref ref="INFO-APPENDER"/>
</appender>
<appender name="ASYNC-ERROR-APPENDER" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丟失日志.默認(rèn)的,如果隊列的80%已滿,則會丟棄TRACT、DEBUG链瓦、INFO級別的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默認(rèn)的隊列的深度,該值會影響性能.默認(rèn)值為256 -->
<queueSize>256</queueSize>
<!-- 添加附加的appender,最多只能添加一個 -->
<appender-ref ref="ERROR-APPENDER"/>
</appender>
<!-- 設(shè)置開發(fā)環(huán)境日志級別為INFO(采用異步輸出的方式) -->
<!-- springProfile 標(biāo)簽下面會講 -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="ASYNC-INFO-APPENDER"/>
</root>
</springProfile>
8.Logback配置文件與Springboot配置文件的配合
1.springProfile標(biāo)簽盯桦,可實現(xiàn)根據(jù)不同的springboot配置文件進(jìn)行不同級別的日志打印
該 <springProfile> 標(biāo)簽允許我們更加靈活配置文件,可選地包含或排除配置部分肥卡。元素中的任何位置均支持輪廓部分事镣。使用該name屬性指定哪個配置文件接受配置》兆粒可以使用逗號分隔列表指定多個配置文件随闪。
<springProfile name="dev">
<!-- 開發(fā)環(huán)境時激活 -->
</springProfile>
<springProfile name="dev,test">
<!-- 開發(fā),測試的時候激活-->
</springProfile>
<springProfile name="!prod">
<!-- 當(dāng) "生產(chǎn)" 環(huán)境時铐伴,該配置不激活-->
</springProfile>
- 案例
<!-- 開發(fā)環(huán)境日志級別為DEBUG -->
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-APPENDER"/>
</root>
</springProfile>
<!-- 測試環(huán)境日志級別為INFO -->
<springProfile name="test">
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-APPENDER"/>
</root>
<!-- 生產(chǎn)環(huán)境日志級別為INFO -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-APPENDER"/>
</root>
</springProfile>
2.springProperty
該 <springProperty> 標(biāo)簽允許我們從Spring中顯示屬性当宴,Environment 以便在Logback中使用。如果你想將 application.properties在回讀配置中訪問文件中的值玲献,這將非常有用。
標(biāo)簽的工作方式與Logback的標(biāo)準(zhǔn) <property> 標(biāo)簽類似捌年,但不是直接value 指定source屬性(從Environment)指定。scope 如果需要將屬性存儲在local范圍之外的其他位置眠砾,則可以使用該屬性托酸。如果您需要一個后備值,以防該屬性未設(shè)置,則Environment可以使用該defaultValue屬性吻育。
<!-- 從Spring環(huán)境變量中獲取值, source屬性是springboot配置文件中的key -->
<springProperty scope="context" name="LOGBACK_NAME" source="springboot.application.name" defaultValue="appName"/>
<!-- 應(yīng)用 通過${name}引入-->
<appender name="EXAMPLE" class="ch.qos.logback.more.appenders.EXAMPLEAppender">
<remoteHost>${LOGBACK_NAME}</remoteHost>
</appender>