本文來(lái)寫(xiě)說(shuō)下logback-spring.xml相關(guān)的知識(shí)與概念
概述
對(duì)于xml日志文件的配置,大多數(shù)人第一次接觸時(shí)有一種望而生畏的感覺(jué),其實(shí)如果仔細(xì)分析,會(huì)發(fā)現(xiàn)核心的部分只有三個(gè)元素:appender、logger、root。
通過(guò)上圖我們可以清晰的了解整個(gè)xml文件的元素及功能。
其中configuration是根元素,必須的;logger和root可視為同一類,都是日志組件;logger定義日志從哪里(包)獲取以及級(jí)別;appender配置日志格式、如何過(guò)濾、文件處理等。property和contextName元素,分別用來(lái)定義變量和應(yīng)用上下文名稱,非必須。
先通過(guò)一個(gè)簡(jiǎn)單的日志模板,從視覺(jué)上感受一下:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %
logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="chapters.configuration" level="INFO"/>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
上述實(shí)例定義了控制臺(tái)輸出debug級(jí)別日志的配置。下面對(duì)相關(guān)的元素進(jìn)行逐一講解。
configuration元素
logback.xml配置文件的基本結(jié)構(gòu)可以描述為configuration元素,包含零個(gè)或多個(gè)appender元素,后跟零個(gè)或多個(gè)logger元素,后跟最多一個(gè)root元素(也可以沒(méi)有)。
根元素configuration有三個(gè)屬性:
- debug:默認(rèn)為false,若設(shè)置為true,則打印出logback內(nèi)部日志信息。
- scan:默認(rèn)值為true,若設(shè)置為true,配置文件如果發(fā)生改變,將會(huì)被重新加載。
- scanPeriod:與scan配合使用,當(dāng)scan為true時(shí),此屬性生效,默認(rèn)的時(shí)間間隔為1分鐘,設(shè)置監(jiān)測(cè)配置文件是否有修改的時(shí)間間隔,如果沒(méi)有給出時(shí)間單位,默認(rèn)單位是毫秒。如可以設(shè)置為scanPeriod="30 seconds"每30秒檢測(cè)一次。
定義上下文名稱
contextName元素,每一個(gè)日志組件(logger)都會(huì)關(guān)聯(lián)到日志上下文,默認(rèn)上下文名稱是’default’,用于標(biāo)識(shí)應(yīng)用,如果多個(gè)應(yīng)用輸出到同一個(gè)地方,就有必要使用%contextName來(lái)區(qū)別。
上線文的配置直接在configuration元素下:
<configuration>
<contextName>HelloWorld-log</contextName>
</configuration>
經(jīng)過(guò)定義之后,在其他property屬性或appender中便可通過(guò)“%contextName”來(lái)獲取和使用該上下文名稱了。
定義變量
通過(guò)property元素可定義變量。它有name和value兩個(gè)屬性。變量可以使“${name}”來(lái)使用變量。作用類似于代碼中的常量字符串,定義之后公共地方便可以統(tǒng)一使用。如日志文件名稱前綴、日志路徑、日志輸出格式等。
<configuration>
<property name="log.path" value="./log" />
</configuration>
上面便是定義了日志的根路徑的變量。
如果是在Spring或SpringBoot項(xiàng)目當(dāng)中,想讓value值是通過(guò)配置文件獲取,可使用springProperty來(lái)定義。
<springProperty scope="context" name="log.path"
source="catalina.base"/>
其中source指定的catalina.base便是在application.properties當(dāng)中配置變量。此配置還是比較常用的,可以做到靈活區(qū)分環(huán)境。
appender組件
appender組件用來(lái)定義日志輸出格式,日志如何過(guò)濾以及日志文件的處理。appender的結(jié)構(gòu)如下:
appender的屬性有name和class。name指定appender名稱,后面使用該appender是也是通過(guò)名稱來(lái)指定。
class屬性指定要實(shí)例化的appender類的完全限定名稱。appender類默認(rèn)有以下幾種:
- ConsoleAppender:日志輸出到控制臺(tái),類名ch.qos.logback.core.ConsoleAppender。
- FileAppender:日志輸入到文件,類名ch.qos.logback.core.FileAppender。
- RollingFileAppender:滾動(dòng)記錄文件,F(xiàn)ileAppender的子類,當(dāng)符合條件(大小、時(shí)間),日志進(jìn)行切分處理。類名:ch.qos.logback.core.rolling.RollingFileAppender。
appender元素可以包含零個(gè)或一個(gè)layout元素,零個(gè)或多個(gè)encoder元素以及零個(gè)或多個(gè)filter元素。
實(shí)戰(zhàn)中ConsoleAppender及RollingFileAppender使用較多,若需要自定義如把日志輸出到消息隊(duì)列,可以自定義實(shí)現(xiàn)AppenderBase接口。
ConsoleAppender上面已經(jīng)有示例,主要作用就是將日志輸出到控制臺(tái),并通過(guò)pattern元素指定了輸出的格式。下面重點(diǎn)看一下RollingFileAppender的配置。
RollingFileAppender配置
RollingFileAppender是FileAppender的子類,擴(kuò)展了FileAppender,具有翻轉(zhuǎn)日志文件的功能。
例如,RollingFileAppender可以記錄到名為log.txt文件的文件,并且一旦滿足某個(gè)條件,就將其日志記錄目標(biāo)更改為另一個(gè)文件。
RollingFileAppender通常包括File、filter,rollingPolicy,encoder和layout元素。
encoder用來(lái)指定日志的輸出格式及編碼等:
<!-- 文件輸出日志格式 -->
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS}
%contextName [%thread] %-5level %logger{36} - %msg%n" />
<appender>
<!--日志文件輸出格式-->
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset class="java.nio.charset.Charset">UTF-8</charset>
</encoder>
</appender>
file元素用來(lái)配置日志的路徑和名稱,一般把路徑和文件名前綴定義到變量(property中)。
<encoder>
<!-- 正在記錄的日志文件的路徑及文件名 -->
<file>${log.path}/log_error.log</file>
</appender>
${log.path}獲取的便是前面屬性中定義的變量。
appender中可以有多個(gè)filter元素,比如用ThresholdFilter來(lái)過(guò)濾低于指定臨界值的日志;用LevelFilter來(lái)過(guò)濾日志級(jí)別。以LevelFilter為例:
<!-- 過(guò)濾器,只記錄debug級(jí)別的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<OnMismatch>DENY</OnMismatch>
<OnMatch>ACCEPT</OnMatch>
</filter>
其中l(wèi)evel指定日志級(jí)別,onMath指定符合過(guò)濾條件的操作接收(ACCEPT),onMismatch指定不符合條件的拒絕(DENY)。
如果需要將不同級(jí)別的日志輸出到不同的日志文件,那么就需要配置多個(gè)filter,每個(gè)filter像上面一樣指定level級(jí)別:DEBUG,INFO,WARN和ERROR。
通常情況下,日志輸出會(huì)配置三個(gè),一個(gè)控制臺(tái)輸出用于開(kāi)發(fā)階段;一個(gè)INFO及以上級(jí)別的日志輸出,可追蹤相應(yīng)的生產(chǎn)日志;一個(gè)單獨(dú)ERROR級(jí)別的日志輸出,方便快速檢查出異常日志。
rollingPolicy用于配置滾動(dòng)策略,支持TimeBasedRollingPolicy、SizeAndTimeBasedRollingPolicy、FixedWindowRollingPolicy、SizeBasedTriggeringPolicy。
分別是基于時(shí)間滾動(dòng)、基于大小和時(shí)間滾動(dòng)、固定窗口滾動(dòng)和大小觸發(fā)。其中FixedWindowRollingPolicy一般和SizeBasedTriggeringPolicy同時(shí)使用。下面以TimeBasedRollingPolicy為例,以天為單位輸出日志,每天一個(gè)日志。
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志輸出格式 -->
<fileNamePattern>${log.path}/debug.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 日志保留天數(shù) -->
<maxHistory>30</maxHistory>
</rollingPolicy>
fileNamePattern指定日志的路徑及名稱,此處是按日期輸出,即%d{yyyy-MM-dd}格式。maxHistory表示日志最多保留天數(shù),存活超過(guò)30天的日志會(huì)被刪除。
logger配置
logger用來(lái)設(shè)置某一個(gè)類或者某個(gè)包的日志輸出級(jí)別、以及關(guān)聯(lián)的appender。
logger包含三個(gè)屬性:
- name:要輸出日志的包名或者類名,比如com.secbro2。必選項(xiàng)。
- level:設(shè)置日志級(jí)別,允許一個(gè)不區(qū)分大小寫(xiě)的字符串值TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF。如果未設(shè)置,則logger會(huì)向上繼承最近一個(gè)非空級(jí)別??蛇x項(xiàng)。
- additivity:是否將日志向上級(jí)傳遞,默認(rèn)為 true??蛇x項(xiàng)。
logger通過(guò)1個(gè)或多個(gè)子節(jié)點(diǎn)appender-ref來(lái)控制日志的輸出。
<logger name="org.springframework" level="WARN"/>
<logger name="com" level="debug" />
上面示例表示org.springframework包下的日志以warn級(jí)別輸出,com包下的日志以debug級(jí)別輸出。
<logger name="com.secbro2" level="info" additivity="true">
<appender-ref ref="CONSOLE" />
</logger>
上面的示例對(duì)指定包指定appender進(jìn)行日志控制,由于設(shè)置了info級(jí)別,additivity為true,而且關(guān)聯(lián)CONSOLE的appender,因此info以上級(jí)別的日志會(huì)輸出到控制臺(tái)。
同時(shí)會(huì)把日志上傳到父級(jí),即root。若root也有配置CONSOLE的輸出的話,會(huì)在控制臺(tái)輸出兩次。additivity為false,則不會(huì)。
root配置
root元素配置根記錄器。它是一個(gè)特殊的logger,是所有l(wèi)ogger的根節(jié)點(diǎn),只有一個(gè)屬性level,默認(rèn)為DEBUG 。
<root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="LOGSTASH" />
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
level屬性的值可以是不區(qū)分大小寫(xiě)的字符串TRACE,DEBUG,INFO,WARN,ERROR,ALL或OFF之一。root元素可以包含零個(gè)或多個(gè)appender-ref元素;被引用的每個(gè)appender都被添加到根記錄器中。
如果是基于SpringBoot項(xiàng)目,針對(duì)不同環(huán)境(profile)有不同的日志輸出,比如開(kāi)發(fā)(dev)環(huán)境只輸出CONSOLE的,生產(chǎn)環(huán)境(prod)只輸入info和error,那則可用到Spring支持的profile機(jī)制。對(duì)應(yīng)的元素為springProfile。
profile的值與springboot中配置文件的spring.profiles.active值進(jìn)行對(duì)照。
<!-- 開(kāi)發(fā)環(huán)境 -->
<springProfile name="dev">
<logger name="com" level="debug" />
<root level="info">
<appender-ref ref="CONSOLE" />
</root>
</springProfile>
<!-- 測(cè)試環(huán)境+生產(chǎn)環(huán)境 -->
<springProfile name="test,prod">
<logger name="com" level="info" />
<root level="info">
<appender-ref ref="INFO_FILE" />
<appender-ref ref="ERROR_FILE" />
</root>
</springProfile>
當(dāng)引入了springProfile,我們可以看到root元素可以出現(xiàn)多次了,但還是保證了一個(gè)環(huán)境只有一個(gè)root元素的要求。springProfile的name對(duì)應(yīng)spring.profiles.active的值,多個(gè)值用逗號(hào)分隔。
ELK的配置
如果項(xiàng)目中的日志采用的是基于ELK(Elasticsearch,Logstash,Kibana三個(gè)開(kāi)源軟件的縮寫(xiě))來(lái)進(jìn)行日志管理。則可以在pom文件中引入logstash-logback-encoder依賴。
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>5.1</version>
</dependency>
然后在logback-spring.xml中配置對(duì)應(yīng)的appender:
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<destination>192.168.0.11:5061</destination>
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"project": "springboot-logback-elk"}</customFields>
</encoder>
</appender>
該appender的使用與其他appender的使用無(wú)異。主要使用了LogstashTcpSocketAppender類來(lái)完成與Logstash的通信。其中destination為L(zhǎng)ogstash提供的服務(wù)地址。customFields為自定義的參數(shù),便于Logstash識(shí)別日志是從哪個(gè)業(yè)務(wù)系統(tǒng)傳輸過(guò)來(lái)的。
輸出logback狀態(tài)數(shù)據(jù)
某些時(shí)候?yàn)榱肆私鈒ogback配置文件加載情況,配置中對(duì)應(yīng)的appender、logger的裝載情況等,我們需要啟用logback狀態(tài)數(shù)據(jù)的輸出。這也是logback官網(wǎng)強(qiáng)烈推薦的,可以幫助我們排除診斷一些問(wèn)題。
啟用狀態(tài)數(shù)據(jù)輸出有兩種方式:
- 在根元素(configuration) 中設(shè)置屬性debug=“true”。
- 添加元素(statusListener),class使用OnConsoleStatusListener。如下:
<!-- 輸出logback的本身狀態(tài)數(shù)據(jù) -->
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
兩種方式選其一即可。第一種方式的debug與配置文件中的日志級(jí)別沒(méi)有關(guān)系,只用于表示輸出狀態(tài)數(shù)據(jù)。
異步輸出日志
前面講到的appender,日志輸出到文件是同步輸出的,即每次輸出都會(huì)直接寫(xiě)IO到磁盤(pán)文件。對(duì)于高并發(fā)的應(yīng)用,會(huì)產(chǎn)生一定的阻塞,造成不必要的性能損耗。
logback提供了日志異步輸出的AsyncAppender。處理方式也很簡(jiǎn)單,添加一個(gè)基于異步寫(xiě)日志的appender,并指向原配置的appender即可:
<!-- 異步輸出 -->
<appender name="ASYNCDEBUG" class="ch.qos.logback.classic.AsyncAppender">
<!-- 默認(rèn)如果隊(duì)列的80%已滿,則會(huì)丟棄TRACT、DEBUG、INFO級(jí)別的日志,若要保留全部日志,設(shè)置為0 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
<queueSize>1024</queueSize>
<!-- 添加附加的appender,最多只能添加一個(gè) -->
<appender-ref ref="DEBUGFILE"/>
<includeCallerData>true</includeCallerData>
</appender>
<!-- 異步輸出關(guān)聯(lián)到root -->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="ASYNCDEBUG" />
//...
</root>
AsyncAppender的實(shí)現(xiàn)原理是通過(guò)阻塞隊(duì)列(BlockingQueue)來(lái)避免日志直接輸出到文件,先把日志事件輸出到BlockingQueue中,然后啟動(dòng)一個(gè)新的worker線程,主線程不阻塞,worker線程則從隊(duì)列中獲取需要寫(xiě)的日志,異步輸出到對(duì)應(yīng)的位置。
代碼中的日志格式
在日常使用日志時(shí),可以通過(guò)最開(kāi)始的示例定義Logger對(duì)象,然后調(diào)用其對(duì)應(yīng)級(jí)別的日志輸出。當(dāng)然,如果采用Lombok的情況下,可直接類上使用@Slf4j注解來(lái)自動(dòng)注入log屬性,不用再聲明:
private static final Logger log = LoggerFactory.getLogger(LogbackController.class);
替換為:
@Slf4j
@RestController
public class LogbackController {
}
其他內(nèi)容不變。
而在日志輸出格式也有多種,其中最不可取的形式是如下模式的日志輸出:
Object entry = new SomeObject();
logger.debug("The entry is " + entry);
這種模式會(huì)導(dǎo)致即使采用info基本輸出,debug中的對(duì)象toString和字符串拼裝依舊會(huì)處理。建議采用如下模式輸出:
Object entry = new SomeObject();
logger.debug("The entry is {}.", entry);
此時(shí),如果日志輸出級(jí)別為info,則不會(huì)處理對(duì)象的toString和字符串的拼接。
logback作者進(jìn)行測(cè)試得出:第一種和第二種寫(xiě)法輸出結(jié)果相同。但在禁用日志記錄語(yǔ)句的情況下,第二種將比第一種寫(xiě)法優(yōu)于至少30倍。
本文小結(jié)
到此,關(guān)于logback日志框架的講解告一段落,如果你還想了解更多底層原理和一些表達(dá)式,建議看一下官方的手冊(cè),雖然是英文的,但還是比較全面的。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-502609.html
本文用巨大篇幅,描述了logback日志常見(jiàn)的使用場(chǎng)景,想必讀到此處時(shí),原來(lái)在那復(fù)雜的日志配置文件已經(jīng)變得十分簡(jiǎn)單吧。趕快嘗試一下吧。用了兩天寫(xiě)完這篇文章,多多支持,你懂得該怎么做的。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-502609.html
到了這里,關(guān)于logback-spring.xml詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!