前言
????套用網(wǎng)絡(luò)流行的標(biāo)題,開始了這篇文章。之前使用Spring Boot,日志一直都是nohup再把標(biāo)準(zhǔn)輸出重定向到一個(gè)文件里,這樣毫無疑問是很low的。于是趁著項(xiàng)目的間歇,照著網(wǎng)上的教程哼哧哼哧的把logback配起來。配完之后,再想想怎么用起來更高大上一點(diǎn),就給自己提了下面幾個(gè)問題:
- 不同級(jí)別的日志怎么輸出到不同的文件?
- 不同服務(wù)的日志怎么輸出到不同的文件?
- 怎么通過一個(gè)traceId把同一次請(qǐng)求里的多條日志串起來?
- 日志的配置怎么在打包時(shí)能根據(jù)不同的環(huán)境去調(diào)整?
- 運(yùn)行中的服務(wù)可以動(dòng)態(tài)的調(diào)整日志級(jí)別么?
????為了解決這些問題,就有了文章標(biāo)題所說的那XX件事。下面將大概介紹下各個(gè)問題的解決方案。最終的成果在代碼中:
????logtest
1.Filter
????第一個(gè)問題的解決方案,就是使用appender中的Filter。logback支持多種Filter,對(duì)于日志級(jí)別的過濾使用LevelFilter。
<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] [%-5level] [%logger{36}:%line] - [%msg]%n
</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/${APP_NAME}/debug.log.%d{yyyy-MM-dd}</FileNamePattern>
<MaxHistory>${LOG_KEEP_TIME}</MaxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
2.logger
????之前配置日志總是喜歡把a(bǔ)ppender都配置在root下,這個(gè)是一種全局的配置,其實(shí)可以通過logger進(jìn)一步細(xì)化。
<logger name="tactics" additivity="false" level="INFO">
<appender-ref ref="tactics"/>
</logger>
????對(duì)應(yīng)的獲取logger方法為:
private final Logger tacticsLogger = LoggerFactory.getLogger("tactics");
????也可以按照我們慣用的方式:
<logger name="com.qcd.logtest.TacticsLogger" additivity="false" level="INFO">
<appender-ref ref="tactics"/>
</logger>
????對(duì)應(yīng)的獲取logger方法為:
private final Logger tacticsLogger = LoggerFactory.getLogger(getClass());
????logger里面有個(gè)很重要的屬性additivity,這個(gè)屬性決定了日志里的內(nèi)容是否會(huì)向上一級(jí)日志傳遞。
3.MDC
????對(duì)于第三個(gè)問題想過自己去封裝一個(gè)日志工具類,通過ThreadLocal的方式來提供uuid,但是總覺得沒那么自然。也看到有人用Spring Cloud Sleuth來達(dá)到目的,又覺得太重。后面發(fā)現(xiàn)了MDC這個(gè)好東西,覺得很滿意。
????MDC(Mapped Diagnostic Context,映射調(diào)試上下文)是 logback 提供的一種方便在多線程條件下記錄日志的功能。MDC 可以看成是一個(gè)與當(dāng)前線程綁定的哈希表,可以往其中添加鍵值對(duì)。
????具體的使用代碼可以參考LogInterceptor.java。
????其中比較關(guān)鍵的兩處如下:
MDC.put("requestId", uuid);
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{requestId}] [%-5level] [%logger{36}:%line] - [%msg]%n
????在pattern中使用的[%X{requestId}]就是來自在MDC中存儲(chǔ)的uuid。
4.logback-spring.xml
????既然加上了spring這么個(gè)后綴,肯定會(huì)給你好處的。
- 可以拿到application.properties里的配置:
<springProperty scope="context" name="logPath" source="logging.path"/>
<property name="LOG_HOME" value="${logPath}"/>
- 可以拿到使用的profile
<springProfile name="test,dev">
<logger name="com.qcd.logtest.TacticsLogger" level="INFO" />
</springProfile>
<springProfile name="pro">
<logger name="com.qcd.logtest.TacticsLogger" level="ERROR" />
</springProfile>
5.actuator
????spring1.5.X版本引入的一個(gè)新的控制端點(diǎn):/loggers,這個(gè)端點(diǎn)非常強(qiáng)大,可以查看當(dāng)前的日志級(jí)別,還可以動(dòng)態(tài)修改日志級(jí)別。比如要修改LogtestController的日志級(jí)別,通過發(fā)送POST請(qǐng)求到:
http://localhost:9011/manage/loggers/com.qcd.logtest.controller.LogtestController
????請(qǐng)求體為:
{
"configuredLevel": "DEBUG"
}
最后
????感謝強(qiáng)大的開源社區(qū),感謝互聯(lián)網(wǎng)上那些無私奉獻(xiàn)的同道?。?!