1. 自定義日志模板參數(shù):Logback的Pattern模板
當(dāng)一個(gè)請(qǐng)求過(guò)來(lái),我們想要知道當(dāng)前請(qǐng)求具體跑了那些流程該怎么做呢? 噔噔噔噔..我們的男主Logback自定義Pattern模板即將登場(chǎng).
在我們打印日志的時(shí)候,通常我們都會(huì)把一些重要的參數(shù)信息寫到日志里面,方便我們后期從日志里面定位問(wèn)題,其他的內(nèi)部系統(tǒng)調(diào)用我們的程序的時(shí)候薇组,我們可以要求他們那邊在header頭里面增加trace-id這樣的唯一標(biāo)識(shí)濒析,如果沒(méi)有該參數(shù)的話拦止,我們自己手動(dòng)生成一個(gè)唯一的標(biāo)識(shí),方便我們將整條請(qǐng)求鏈路構(gòu)建起來(lái).
<property name="CONSOLE_LOG_PATTERN" value="[%yellow(%date{yyyy-MM-dd HH:mm:ss})] [%highlight(%-5level)] [%cyan(%traceId)] [%magenta(%thread)] [%blue(%file:%line)] [%green(%logger)] : %.4000m%n"/>
上面這里是Logback的定義變量,重點(diǎn)關(guān)注[%cyan(%traceId)]這個(gè)參數(shù)(ps:其他的日志系統(tǒng)如log4j2都有類似的實(shí)現(xiàn)
要實(shí)現(xiàn)讓Logback識(shí)別我們自定義的標(biāo)識(shí)符,我們需要繼承兩個(gè)方法ClassicConverter跟PatternLayout,具體實(shí)現(xiàn)如下:
public classPatternLogbackLayoutextendsPatternLayout{
? static {
? ? defaultConverterMap.put("traceId", TraceIdPatternConverter.class.getName());
? }
}public classTraceIdPatternConverterextendsClassicConverter{
@Override publicStringconvert(ILoggingEvent iLoggingEvent){
String traceId = LogHandlerInterceptor.getTrack();
return StringUtils.isEmpty(traceId) ? "traceId" : traceId;
}
}
通過(guò)spring的攔截器我們將請(qǐng)求的header頭里面的參數(shù)賦值給traceId,然后配置logback.xml和橙,讓logback去識(shí)別我們定義的traceId
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
? <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
? ? ? <layout class="com.blacksearch.logback.PatternLogbackLayout">
? ? ? <pattern>${CONSOLE_LOG_PATTERN}</pattern>
? ? ? </layout>
? </encoder>
</appender>
通過(guò)以上配置,我們已經(jīng)可以在日志里面看到traceId了
[2019-05-10 16:47:38] [INFO ] [538e2c0d-3800-4c86-b320-260bdd945c0c] [http-nio-8080-exec-6] [TestLogTrackController.java:15] [com.blacksearch.controller.TestLogTrackController] : 測(cè)試
[2019-05-10 16:47:38] [DEBUG] [538e2c0d-3800-4c86-b320-260bdd945c0c] [http-nio-8080-exec-6] [AbstractMessageConverterMethodProcessor.java:298] [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor] : Nothing to write: null body
這樣子在服務(wù)器上面我們可以通過(guò)
grep '538e2c0d-3800-4c86-b320-260bdd945c0c'
查看到當(dāng)前請(qǐng)求的所有日志~或者上ELK之后 直接搜索538e2c0d-3800-4c86-b320-260bdd945c0c 方便開(kāi)心~
2. 當(dāng)我們使用多線程的時(shí)候,我們發(fā)現(xiàn),原先定義的標(biāo)識(shí)居然消失了T冶颉!顺囊!
@RequestMapping("/asynLogTrack")publicStringasynLogTrack(){
logger.info("ces--------");
new Thread(new Runnable() {
@Override publicvoidrun(){
logger.info("ces");
}
}).start();
return null;
}
[2019-05-10 16:55:18] [INFO ] [5b446567-97be-42f7-b6b0-205a6b431e87] [http-nio-8080-exec-2] [TestLogTrackController.java:21] [com.blacksearch.controller.TestLogTrackController] : ces--------
[2019-05-10 16:55:18] [INFO ] [traceId] [Thread-10] [TestLogTrackController.java:25] [com.blacksearch.controller.TestLogTrackController] : ces
[2019-05-10 16:55:18] [DEBUG] [5b446567-97be-42f7-b6b0-205a6b431e87] [http-nio-8080-exec-2] [AbstractMessageConverterMethodProcessor.java:298] [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor] : Nothing to write: null body
我們看到打印 ces 的打印記錄,我們發(fā)現(xiàn),traceId居然丟失了!!! 原因在于,棧是線程私有,當(dāng)我們新建線程的時(shí)候,新建的線程跟原來(lái)的線程互相獨(dú)立,也就是說(shuō)logback無(wú)法在新建的線程上獲取到值蕉拢。既然如何,那么我們?cè)撊绾巫孡ogback在新線程上獲取到值呢特碳?正如標(biāo)題而言诚亚。
public abstract classTrackRunnableimplementsRunnable{
publicabstractvoidtrackRun();
private String track = LogHandlerInterceptor.getTrack();
@Override publicvoidrun(){
try {
LogHandlerInterceptor.setTrace(track);
trackRun();
}finally {
LogHandlerInterceptor.remove();
}
}
}
我們采用抽象類實(shí)現(xiàn)Runnable,然后在run()方法里面通過(guò)ThreadLocal去重新賦值。eg:
@RequestMapping("/asynLogTrackHasTrace")publicStringasynLogTrackHasTrace(){
logger.info("ces1------");
new Thread(new TrackRunnable() {
@Override publicvoidtrackRun(){
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("ces2-----------");
}
}).start();
return null;
}
[2019-05-10 17:07:20] [INFO ] [0a7f30d3-8e1d-49b4-9bca-4b72fd1c0ccd] [http-nio-8080-exec-5] [TestLogTrackController.java:33] [com.blacksearch.controller.TestLogTrackController] : ces1------
[2019-05-10 17:07:20] [DEBUG] [0a7f30d3-8e1d-49b4-9bca-4b72fd1c0ccd] [http-nio-8080-exec-5] [AbstractMessageConverterMethodProcessor.java:298] [org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor] : Nothing to write: null body
[2019-05-10 17:07:20] [DEBUG] [traceId] [http-nio-8080-exec-5] [FrameworkServlet.java:1130] [org.springframework.web.servlet.DispatcherServlet] : Completed 200 OK
[2019-05-10 17:07:24] [INFO ] [0a7f30d3-8e1d-49b4-9bca-4b72fd1c0ccd] [Thread-11] [TestLogTrackController.java:42] [com.blacksearch.controller.TestLogTrackController] : ces2-----------
覺(jué)得不錯(cuò)請(qǐng)點(diǎn)贊支持午乓,歡迎留言或進(jìn)我的個(gè)人群855801563領(lǐng)取【架構(gòu)資料專題目合集90期】站宗、【BATJTMD大廠JAVA面試真題1000+】,本群專用于學(xué)習(xí)交流技術(shù)益愈、分享面試機(jī)會(huì)梢灭,拒絕廣告,我也會(huì)在群內(nèi)不定期答題蒸其、探討敏释。