Logback配置文件這么寫(xiě),還說(shuō)你不會(huì)整理日志?
摘要:
1.日志輸出到文件并根據(jù)LEVEL級(jí)別將日志分類保存到不同文件
2.通過(guò)異步輸出日志減少磁盤IO提高性能
3.異步輸出日志的原理
1、配置文件logback-spring.xml
SpringBoot工程自帶logback和slf4j的依賴,所以重點(diǎn)放在編寫(xiě)配置文件上,需要引入什么依賴,日志依賴沖突統(tǒng)統(tǒng)都不需要我們管了。
logback框架會(huì)默認(rèn)加載classpath下命名為logback-spring.xml或logback.xml的配置文件。
如果將所有日志都存儲(chǔ)在一個(gè)文件中,文件大小也隨著應(yīng)用的運(yùn)行越來(lái)越大并且不好排查問(wèn)題,正確的做法應(yīng)該是將error日志和其他日志分開(kāi),并且不同級(jí)別的日志根據(jù)時(shí)間段進(jìn)行記錄存儲(chǔ)。
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<!-- 項(xiàng)目名稱 -->
<property name="PROJECT_NAME" value="project-api" />
<!--定義日志文件的存儲(chǔ)地址 勿在 LogBack 的配置中使用相對(duì)路徑-->
<property name="LOG_HOME" value="logs" />
<!-- 控制臺(tái)輸出 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>true</withJansi>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 格式化輸出: %d: 日期; %-5level: 級(jí)別從左顯示5個(gè)字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號(hào); %msg: 日志消息; %n: 換行符 -->
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line] - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- ERROR日志文件,記錄錯(cuò)誤日志 -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${PROJECT_NAME}/error.log</file>
<!-- 過(guò)濾器,只打印ERROR級(jí)別的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志文件輸出的文件名-->
<FileNamePattern>${LOG_HOME}/${PROJECT_NAME}/%d{yyyy-MM-dd}/error.%i.zip</FileNamePattern>
<!--日志文件保留天數(shù)-->
<MaxHistory>3650</MaxHistory>
<!--日志文件最大的大小-->
<MaxFileSize>100MB</MaxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 格式化輸出: %d: 日期; %-5level: 級(jí)別從左顯示5個(gè)字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號(hào); %msg: 日志消息; %n: 換行符 -->
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line] - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- INFO日志文件,用于記錄重要日志信息 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${PROJECT_NAME}/info.log</file>
<!-- 過(guò)濾器,只打印INFO級(jí)別的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志文件輸出的文件名-->
<FileNamePattern>${LOG_HOME}/${PROJECT_NAME}/%d{yyyy-MM-dd}/info.%i.zip</FileNamePattern>
<!--日志文件保留天數(shù)-->
<MaxHistory>3650</MaxHistory>
<!--日志文件最大的大小-->
<MaxFileSize>100MB</MaxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 格式化輸出: %d: 日期; %-5level: 級(jí)別從左顯示5個(gè)字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號(hào); %msg: 日志消息; %n: 換行符 -->
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line] - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 打印的SQL日志文件,用于執(zhí)行的SQL語(yǔ)句和參數(shù)信息 -->
<appender name="SQL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${PROJECT_NAME}/sql.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志文件輸出的文件名-->
<FileNamePattern>${LOG_HOME}/${PROJECT_NAME}/%d{yyyy-MM-dd}/sql.%i.zip</FileNamePattern>
<!--日志文件保留天數(shù)-->
<MaxHistory>3650</MaxHistory>
<!--日志文件最大的大小-->
<MaxFileSize>100MB</MaxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 格式化輸出: %d: 日期; %-5level: 級(jí)別從左顯示5個(gè)字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號(hào); %msg: 日志消息; %n: 換行符 -->
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line] - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- API請(qǐng)求被訪問(wèn)的日志文件,記錄請(qǐng)求的URL和攜帶的參數(shù) -->
<appender name="REQUEST_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${PROJECT_NAME}/request.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--日志文件輸出的文件名-->
<FileNamePattern>${LOG_HOME}/${PROJECT_NAME}/%d{yyyy-MM-dd}/request.%i.zip</FileNamePattern>
<!--日志文件保留天數(shù)-->
<MaxHistory>3650</MaxHistory>
<!--日志文件最大的大小-->
<MaxFileSize>100MB</MaxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 格式化輸出: %d: 日期; %-5level: 級(jí)別從左顯示5個(gè)字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號(hào); %msg: 日志消息; %n: 換行符 -->
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] [%logger{50}] [%M] [%line]- %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 異步輸出INFO_FILE -->
<appender name="ASYNC_INFO_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
<queueSize>256</queueSize>
<!-- 默認(rèn)情況下,當(dāng)阻塞隊(duì)列的剩余容量為20%時(shí),它將丟棄TRACE,DEBUG和INFO級(jí)別的事件,僅保留WARN和ERROR級(jí)別的事件。要保留所有事件,請(qǐng)將discardingThreshold設(shè)置為0。 -->
<discardingThreshold>0</discardingThreshold>
<!-- 添加附加的appender,使用前面定義的name,最多只能添加一個(gè) -->
<appender-ref ref="INFO_FILE"/>
</appender>
<!-- 異步輸出ERROR_FILE -->
<appender name="ASYNC_ERROR_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
<queueSize>256</queueSize>
<!-- 默認(rèn)情況下,當(dāng)阻塞隊(duì)列的剩余容量為20%時(shí),它將丟棄TRACE,DEBUG和INFO級(jí)別的事件,僅保留WARN和ERROR級(jí)別的事件。要保留所有事件,請(qǐng)將discardingThreshold設(shè)置為0。 -->
<discardingThreshold>0</discardingThreshold>
<!-- 添加附加的appender,使用前面定義的name,最多只能添加一個(gè) -->
<appender-ref ref="ERROR_FILE"/>
</appender>
<!-- 異步輸出SQL_FILE -->
<appender name="ASYNC_SQL_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
<queueSize>256</queueSize>
<!-- 默認(rèn)情況下,當(dāng)阻塞隊(duì)列的剩余容量為20%時(shí),它將丟棄TRACE,DEBUG和INFO級(jí)別的事件,僅保留WARN和ERROR級(jí)別的事件。要保留所有事件,請(qǐng)將discardingThreshold設(shè)置為0。 -->
<discardingThreshold>0</discardingThreshold>
<!-- 添加附加的appender,使用前面定義的name,最多只能添加一個(gè) -->
<appender-ref ref="SQL_FILE"/>
</appender>
<!-- 異步輸出REQUEST_FILE -->
<appender name="ASYNC_REQUEST_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
<queueSize>256</queueSize>
<!-- 默認(rèn)情況下,當(dāng)阻塞隊(duì)列的剩余容量為20%時(shí),它將丟棄TRACE,DEBUG和INFO級(jí)別的事件,僅保留WARN和ERROR級(jí)別的事件。要保留所有事件,請(qǐng)將discardingThreshold設(shè)置為0。 -->
<discardingThreshold>0</discardingThreshold>
<!-- 添加附加的appender,使用前面定義的name,最多只能添加一個(gè) -->
<appender-ref ref="REQUEST_FILE"/>
</appender>
<!-- 輸出error信息到文件-->
<logger name="error" additivity="true">
<appender-ref ref="ERROR_FILE"/>
</logger>
<!-- 輸出info信息到文件-->
<logger name="info" additivity="true">
<appender-ref ref="INFO_FILE"/>
</logger>
<!-- 輸出request信息到文件-->
<logger name="request" level="INFO" additivity="false">
<appender-ref ref="REQUEST_FILE" />
</logger>
<!-- 輸出SQL到控制臺(tái)和文件-->
<logger name="org.hibernate.SQL" additivity="false">
<level value="DEBUG" />
<appender-ref ref="SQL_FILE" />
</logger>
<!-- 輸出SQL的參數(shù)到控制臺(tái)和文件-->
<logger name="org.hibernate.type.descriptor.sql.BasicBinder" additivity="false" level="TRACE">
<level value="TRACE" />
<appender-ref ref="SQL_FILE" />
</logger>
<!-- 開(kāi)發(fā)環(huán)境下的日志配置 -->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="INFO_FILE" />
</root>
</springProfile>
<!-- 測(cè)試環(huán)境下的日志配置 -->
<springProfile name="test">
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="INFO_FILE" />
</root>
</springProfile>
<!-- 生產(chǎn)環(huán)境下的日志配置 -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="ERROR_FILE" />
<appender-ref ref="INFO_FILE" />
</root>
</springProfile>
</configuration>
標(biāo)簽說(shuō)明:
<root>標(biāo)簽,必填標(biāo)簽,用來(lái)指定最基礎(chǔ)的日志輸出級(jí)別
<appender-ref>標(biāo)簽,添加append
<append>標(biāo)簽,通過(guò)使用該標(biāo)簽指定日志的收集策略
<filter>標(biāo)簽,通過(guò)使用該標(biāo)簽指定過(guò)濾策略
<level>標(biāo)簽指定過(guò)濾的類型
<encoder>標(biāo)簽,使用該標(biāo)簽下的<pattern>標(biāo)簽指定日志輸出格式
<rollingPolicy>標(biāo)簽指定收集策略,比如基于時(shí)間進(jìn)行收集
<fileNamePattern>標(biāo)簽指定生成日志保存地址,通過(guò)這樣配置已經(jīng)實(shí)現(xiàn)了分類分日期收集日志的目標(biāo)了
name屬性指定appender命名
class屬性指定輸出策略,通常有兩種,控制臺(tái)輸出和文件輸出,文件輸出就是將日志進(jìn)行一個(gè)持久化
ConsoleAppender將日志輸出到控制臺(tái)
部分截圖展示:
目錄:

error.log

info.log

sql.log

request.log

2、logback 高級(jí)特性異步輸出日志
如果不配置異步輸出規(guī)則,那么默認(rèn)日志配置方式是基于同步的,每次日志輸出到文件都會(huì)進(jìn)行一次磁盤IO。
采用異步寫(xiě)日志的方式而不讓此次寫(xiě)日志發(fā)生磁盤IO,阻塞線程從而造成不必要的性能損耗。
異步輸出日志的方式很簡(jiǎn)單,添加一個(gè)基于異步寫(xiě)日志的appender,并指向原先配置的appender即可。
異步輸出配置:
<!-- 異步輸出INFO_FILE -->
<appender name="ASYNC_INFO_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
<queueSize>256</queueSize>
<!-- 默認(rèn)情況下,當(dāng)阻塞隊(duì)列的剩余容量為20%時(shí),它將丟棄TRACE,DEBUG和INFO級(jí)別的事件,僅保留WARN和ERROR級(jí)別的事件。要保留所有事件,請(qǐng)將discardingThreshold設(shè)置為0。 -->
<discardingThreshold>0</discardingThreshold>
<!-- 添加附加的appender,使用前面定義的name,最多只能添加一個(gè) -->
<appender-ref ref="INFO_FILE"/>
</appender>
<!-- 異步輸出ERROR_FILE -->
<appender name="ASYNC_ERROR_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
<queueSize>256</queueSize>
<!-- 默認(rèn)情況下,當(dāng)阻塞隊(duì)列的剩余容量為20%時(shí),它將丟棄TRACE,DEBUG和INFO級(jí)別的事件,僅保留WARN和ERROR級(jí)別的事件。要保留所有事件,請(qǐng)將discardingThreshold設(shè)置為0。 -->
<discardingThreshold>0</discardingThreshold>
<!-- 添加附加的appender,使用前面定義的name,最多只能添加一個(gè) -->
<appender-ref ref="ERROR_FILE"/>
</appender>
<!-- 異步輸出SQL_FILE -->
<appender name="ASYNC_SQL_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
<queueSize>256</queueSize>
<!-- 默認(rèn)情況下,當(dāng)阻塞隊(duì)列的剩余容量為20%時(shí),它將丟棄TRACE,DEBUG和INFO級(jí)別的事件,僅保留WARN和ERROR級(jí)別的事件。要保留所有事件,請(qǐng)將discardingThreshold設(shè)置為0。 -->
<discardingThreshold>0</discardingThreshold>
<!-- 添加附加的appender,使用前面定義的name,最多只能添加一個(gè) -->
<appender-ref ref="SQL_FILE"/>
</appender>
<!-- 異步輸出REQUEST_FILE -->
<appender name="ASYNC_REQUEST_FILE" class="ch.qos.logback.classic.AsyncAppender">
<!-- 更改默認(rèn)的隊(duì)列的深度,該值會(huì)影響性能.默認(rèn)值為256 -->
<queueSize>256</queueSize>
<!-- 默認(rèn)情況下,當(dāng)阻塞隊(duì)列的剩余容量為20%時(shí),它將丟棄TRACE,DEBUG和INFO級(jí)別的事件,僅保留WARN和ERROR級(jí)別的事件。要保留所有事件,請(qǐng)將discardingThreshold設(shè)置為0。 -->
<discardingThreshold>0</discardingThreshold>
<!-- 添加附加的appender,使用前面定義的name,最多只能添加一個(gè) -->
<appender-ref ref="REQUEST_FILE"/>
</appender>
參數(shù)配置:
| 參數(shù)名稱 | 參數(shù)類型 | 建議值 | 說(shuō)明 |
| queueSize | int | queueSize計(jì)算 example:假設(shè)IO影響30s,日志和qps比例是1:1,單容器壓測(cè)值1500 qps則可以推算出queue size的值,queueSize的設(shè)置公式:30 *1500=45000。 |
阻塞隊(duì)列的最大容量。默認(rèn)情況下,queueSize設(shè)置為256。 |
| discardingThreshold | int |
使用默認(rèn)值20,或者設(shè)置大于0。 如果設(shè)置discardingThreshold=0,表示queue 滿了,不丟棄,block線程。 |
默認(rèn)情況下,當(dāng)阻塞隊(duì)列剩余20%的容量時(shí),它將丟棄級(jí)別跟蹤、調(diào)試和信息事件,只保留級(jí)別警告和錯(cuò)誤事件。要保留所有事件,請(qǐng)將discardingThreshold設(shè)置為0。 |
| neverBlock | boolean | true | 如果為false(默認(rèn)值),則追加程序?qū)⒆柚棺芳拥酵暾?duì)列,而不是丟失消息。設(shè)置為true時(shí),附加程序只會(huì)丟棄消息,不會(huì)阻止您的應(yīng)用程序。 |
官方文檔鏈接:http://logback.qos.ch/manual/appenders.html
3、異步日志輸出原理
異步輸出日志中最關(guān)鍵的就是配置文件中ch.qos.logback.classic包下AsyncAppenderBase類中的append方法,查看該方法的源碼:
@Override
protected void append(E eventObject) {
if (isQueueBelowDiscardingThreshold() && isDiscardable(eventObject)) {
return;
}
preprocess(eventObject);
put(eventObject);
}
通過(guò)隊(duì)列情況判斷是否需要丟棄日志,不丟棄的話將它放到阻塞隊(duì)列中,通過(guò)查看代碼,這個(gè)阻塞隊(duì)列為queueSize,默認(rèn)大小為256,可以通過(guò)配置文件進(jìn)行修改。
/** * The default buffer size. */ public static final int DEFAULT_QUEUE_SIZE = 256; int queueSize = DEFAULT_QUEUE_SIZE;
Logger.info(...)到append(...)就結(jié)束了,只做了將日志塞入到阻塞隊(duì)列的事,然后繼續(xù)執(zhí)行Logger.info(...)下面的語(yǔ)句了。在AsyncAppenderBase類中定義了一個(gè)Worker線程,run()方法中的代碼如下:
class Worker extends Thread {
public void run() {
AsyncAppenderBase<E> parent = AsyncAppenderBase.this;
AppenderAttachableImpl<E> aai = parent.aai;
// loop while the parent is started
while (parent.isStarted()) {
try {
E e = parent.blockingQueue.take();
aai.appendLoopOnAppenders(e);
} catch (InterruptedException ie) {
break;
}
}
addInfo("Worker thread will flush remaining events before exiting. ");
for (E e : parent.blockingQueue) {
aai.appendLoopOnAppenders(e);
parent.blockingQueue.remove(e);
}
aai.detachAndStopAllAppenders();
}
}
從阻塞隊(duì)列中取出一個(gè)日志,并調(diào)用AppenderAttachableImpl類中的appendLoopOnAppenders方法維護(hù)一個(gè)Append列表。

最主要的兩個(gè)方法就是encode和write方法,前一個(gè)法方會(huì)根據(jù)配置文件中encode指定的方式轉(zhuǎn)化為字節(jié)碼,后一個(gè)方法將轉(zhuǎn)化成的字節(jié)碼寫(xiě)入到文件中去。
所以寫(xiě)文件是通過(guò)新起一個(gè)線程去完成的,主線程將日志放到阻塞隊(duì)列中,然后又去執(zhí)行其他任務(wù)。
到此這篇關(guān)于Logback配置文件這么寫(xiě),還說(shuō)你不會(huì)整理日志?的文章就介紹到這了,更多相關(guān)Logback配置文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
初學(xué)者易上手的SSH-struts2 01環(huán)境搭建(圖文教程)
下面小編就為大家?guī)?lái)一篇初學(xué)者易上手的SSH-struts2 01環(huán)境搭建(圖文教程)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
MyBatis實(shí)現(xiàn)批量插入方法實(shí)例
最近在公司項(xiàng)目開(kāi)發(fā)中遇到批量數(shù)據(jù)插入或者更新,下面這篇文章主要給大家介紹了關(guān)于MyBatis實(shí)現(xiàn)批量插入的相關(guān)資料,需要的朋友可以參考下2022-10-10
Spring Boot 2.X整合Spring-cache(讓你的網(wǎng)站速度飛起來(lái))
這篇文章主要介紹了Spring Boot 2.X整合Spring-cache(讓你的網(wǎng)站速度飛起來(lái)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Java IO流之節(jié)點(diǎn)流與字符流的相關(guān)知識(shí)總結(jié)
今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Java節(jié)點(diǎn)流與字符流展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
Mybatis-Plus自動(dòng)填充更新操作相關(guān)字段的實(shí)現(xiàn)
這篇文章主要介紹了Mybatis-Plus自動(dòng)填充更新操作相關(guān)字段的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12

