Logback配置文件這么寫,還說你不會整理日志?
摘要:
1.日志輸出到文件并根據(jù)LEVEL級別將日志分類保存到不同文件
2.通過異步輸出日志減少磁盤IO提高性能
3.異步輸出日志的原理
1、配置文件logback-spring.xml
SpringBoot
工程自帶logback和slf4j
的依賴,所以重點放在編寫配置文件上,需要引入什么依賴,日志依賴沖突統(tǒng)統(tǒng)都不需要我們管了。
logback
框架會默認加載classpath下命名為logback-spring.xml
或logback.xml
的配置文件。
如果將所有日志都存儲在一個文件中,文件大小也隨著應(yīng)用的運行越來越大并且不好排查問題,正確的做法應(yīng)該是將error日志和其他日志分開,并且不同級別的日志根據(jù)時間段進行記錄存儲。
配置文件:
<?xml version="1.0" encoding="UTF-8"?> <configuration debug="true"> <!-- 項目名稱 --> <property name="PROJECT_NAME" value="project-api" /> <!--定義日志文件的存儲地址 勿在 LogBack 的配置中使用相對路徑--> <property name="LOG_HOME" value="logs" /> <!-- 控制臺輸出 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <withJansi>true</withJansi> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <!-- 格式化輸出: %d: 日期; %-5level: 級別從左顯示5個字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號; %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日志文件,記錄錯誤日志 --> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_HOME}/${PROJECT_NAME}/error.log</file> <!-- 過濾器,只打印ERROR級別的日志 --> <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: 級別從左顯示5個字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號; %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> <!-- 過濾器,只打印INFO級別的日志 --> <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: 級別從左顯示5個字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號; %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語句和參數(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: 級別從左顯示5個字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號; %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請求被訪問的日志文件,記錄請求的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: 級別從左顯示5個字符寬度; %thread: 線程名; %logger: 類名; %M: 方法名; %line: 行號; %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"> <!-- 更改默認的隊列的深度,該值會影響性能.默認值為256 --> <queueSize>256</queueSize> <!-- 默認情況下,當阻塞隊列的剩余容量為20%時,它將丟棄TRACE,DEBUG和INFO級別的事件,僅保留WARN和ERROR級別的事件。要保留所有事件,請將discardingThreshold設(shè)置為0。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="INFO_FILE"/> </appender> <!-- 異步輸出ERROR_FILE --> <appender name="ASYNC_ERROR_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認的隊列的深度,該值會影響性能.默認值為256 --> <queueSize>256</queueSize> <!-- 默認情況下,當阻塞隊列的剩余容量為20%時,它將丟棄TRACE,DEBUG和INFO級別的事件,僅保留WARN和ERROR級別的事件。要保留所有事件,請將discardingThreshold設(shè)置為0。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="ERROR_FILE"/> </appender> <!-- 異步輸出SQL_FILE --> <appender name="ASYNC_SQL_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認的隊列的深度,該值會影響性能.默認值為256 --> <queueSize>256</queueSize> <!-- 默認情況下,當阻塞隊列的剩余容量為20%時,它將丟棄TRACE,DEBUG和INFO級別的事件,僅保留WARN和ERROR級別的事件。要保留所有事件,請將discardingThreshold設(shè)置為0。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="SQL_FILE"/> </appender> <!-- 異步輸出REQUEST_FILE --> <appender name="ASYNC_REQUEST_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認的隊列的深度,該值會影響性能.默認值為256 --> <queueSize>256</queueSize> <!-- 默認情況下,當阻塞隊列的剩余容量為20%時,它將丟棄TRACE,DEBUG和INFO級別的事件,僅保留WARN和ERROR級別的事件。要保留所有事件,請將discardingThreshold設(shè)置為0。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <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到控制臺和文件--> <logger name="org.hibernate.SQL" additivity="false"> <level value="DEBUG" /> <appender-ref ref="SQL_FILE" /> </logger> <!-- 輸出SQL的參數(shù)到控制臺和文件--> <logger name="org.hibernate.type.descriptor.sql.BasicBinder" additivity="false" level="TRACE"> <level value="TRACE" /> <appender-ref ref="SQL_FILE" /> </logger> <!-- 開發(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> <!-- 測試環(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>
標簽說明:
<root>標簽,必填標簽,用來指定最基礎(chǔ)的日志輸出級別
<appender-ref>標簽,添加append
<append>標簽,通過使用該標簽指定日志的收集策略
<filter>標簽,通過使用該標簽指定過濾策略
<level>標簽指定過濾的類型
<encoder>標簽,使用該標簽下的<pattern>標簽指定日志輸出格式
<rollingPolicy>標簽指定收集策略,比如基于時間進行收集
<fileNamePattern>標簽指定生成日志保存地址,通過這樣配置已經(jīng)實現(xiàn)了分類分日期收集日志的目標了
name屬性指定appender命名
class屬性指定輸出策略,通常有兩種,控制臺輸出和文件輸出,文件輸出就是將日志進行一個持久化
ConsoleAppender將日志輸出到控制臺
部分截圖展示:
目錄:
error.log
info.log
sql.log
request.log
2、logback 高級特性異步輸出日志
如果不配置異步輸出規(guī)則,那么默認日志配置方式是基于同步的,每次日志輸出到文件都會進行一次磁盤IO。
采用異步寫日志的方式而不讓此次寫日志發(fā)生磁盤IO,阻塞線程從而造成不必要的性能損耗。
異步輸出日志的方式很簡單,添加一個基于異步寫日志的appender,并指向原先配置的appender
即可。
異步輸出配置:
<!-- 異步輸出INFO_FILE --> <appender name="ASYNC_INFO_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認的隊列的深度,該值會影響性能.默認值為256 --> <queueSize>256</queueSize> <!-- 默認情況下,當阻塞隊列的剩余容量為20%時,它將丟棄TRACE,DEBUG和INFO級別的事件,僅保留WARN和ERROR級別的事件。要保留所有事件,請將discardingThreshold設(shè)置為0。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="INFO_FILE"/> </appender> <!-- 異步輸出ERROR_FILE --> <appender name="ASYNC_ERROR_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認的隊列的深度,該值會影響性能.默認值為256 --> <queueSize>256</queueSize> <!-- 默認情況下,當阻塞隊列的剩余容量為20%時,它將丟棄TRACE,DEBUG和INFO級別的事件,僅保留WARN和ERROR級別的事件。要保留所有事件,請將discardingThreshold設(shè)置為0。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="ERROR_FILE"/> </appender> <!-- 異步輸出SQL_FILE --> <appender name="ASYNC_SQL_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認的隊列的深度,該值會影響性能.默認值為256 --> <queueSize>256</queueSize> <!-- 默認情況下,當阻塞隊列的剩余容量為20%時,它將丟棄TRACE,DEBUG和INFO級別的事件,僅保留WARN和ERROR級別的事件。要保留所有事件,請將discardingThreshold設(shè)置為0。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="SQL_FILE"/> </appender> <!-- 異步輸出REQUEST_FILE --> <appender name="ASYNC_REQUEST_FILE" class="ch.qos.logback.classic.AsyncAppender"> <!-- 更改默認的隊列的深度,該值會影響性能.默認值為256 --> <queueSize>256</queueSize> <!-- 默認情況下,當阻塞隊列的剩余容量為20%時,它將丟棄TRACE,DEBUG和INFO級別的事件,僅保留WARN和ERROR級別的事件。要保留所有事件,請將discardingThreshold設(shè)置為0。 --> <discardingThreshold>0</discardingThreshold> <!-- 添加附加的appender,使用前面定義的name,最多只能添加一個 --> <appender-ref ref="REQUEST_FILE"/> </appender>
參數(shù)配置:
參數(shù)名稱 | 參數(shù)類型 | 建議值 | 說明 |
queueSize | int | queueSize計算 example:假設(shè)IO影響30s,日志和qps比例是1:1,單容器壓測值1500 qps則可以推算出queue size的值,queueSize的設(shè)置公式:30 *1500=45000。 |
阻塞隊列的最大容量。默認情況下,queueSize設(shè)置為256。 |
discardingThreshold | int |
使用默認值20,或者設(shè)置大于0。 如果設(shè)置discardingThreshold=0,表示queue 滿了,不丟棄,block線程。 |
默認情況下,當阻塞隊列剩余20%的容量時,它將丟棄級別跟蹤、調(diào)試和信息事件,只保留級別警告和錯誤事件。要保留所有事件,請將discardingThreshold設(shè)置為0。 |
neverBlock | boolean | true | 如果為false(默認值),則追加程序?qū)⒆柚棺芳拥酵暾犃?,而不是丟失消息。設(shè)置為true時,附加程序只會丟棄消息,不會阻止您的應(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); }
通過隊列情況判斷是否需要丟棄日志,不丟棄的話將它放到阻塞隊列中,通過查看代碼,這個阻塞隊列為queueSize,默認大小為256,可以通過配置文件進行修改。
/** * The default buffer size. */ public static final int DEFAULT_QUEUE_SIZE = 256; int queueSize = DEFAULT_QUEUE_SIZE;
Logger.info(...)到append(...)就結(jié)束了,只做了將日志塞入到阻塞隊列的事,然后繼續(xù)執(zhí)行Logger.info(...)下面的語句了。在AsyncAppenderBase類中定義了一個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(); } }
從阻塞隊列中取出一個日志,并調(diào)用AppenderAttachableImpl類中的appendLoopOnAppenders方法維護一個Append列表。
最主要的兩個方法就是encode和write方法,前一個法方會根據(jù)配置文件中encode指定的方式轉(zhuǎn)化為字節(jié)碼,后一個方法將轉(zhuǎn)化成的字節(jié)碼寫入到文件中去。
所以寫文件是通過新起一個線程去完成的,主線程將日志放到阻塞隊列中,然后又去執(zhí)行其他任務(wù)。
到此這篇關(guān)于Logback配置文件這么寫,還說你不會整理日志?的文章就介紹到這了,更多相關(guān)Logback配置文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實現(xiàn)File轉(zhuǎn)換MultipartFile格式的例子
本文主要介紹了Java實現(xiàn)File轉(zhuǎn)換MultipartFile格式的例子,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07Jeecg-Boot異常處理'jeecg-boot.QRTZ_LOCKS'?doesn'
這篇文章主要介紹了Jeecg-Boot異常處理'jeecg-boot.QRTZ_LOCKS'?doesn't?exist問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12mysql+spring+mybatis實現(xiàn)數(shù)據(jù)庫讀寫分離的代碼配置
今天小編就為大家分享一篇關(guān)于mysql+spring+mybatis實現(xiàn)數(shù)據(jù)庫讀寫分離的代碼配置,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03SpringBoot整合MybatisPlus的基本應(yīng)用詳解
MyBatis-Plus (簡稱 MP)是一個 MyBatis的增強工具,在 MyBatis 的基礎(chǔ)上只做增強不做改變,為 簡化開發(fā)、提高效率而生,本文將給大家介紹一下SpringBoot整合MybatisPlus的基本應(yīng)用,需要的朋友可以參考下2024-05-05