基于Slf4j的MDC实现日志链路串联
基于Slf4j的MDC實現(xiàn)日志鏈路串聯(lián)
一 、問題背景
為了方便運維日常定位排查問題時,使用traceId查詢?nèi)罩緯r可以完整的查看當前業(yè)務(wù)請求的完整日志鏈路,需使用traceId(日志跟蹤號)將日志串聯(lián)起來。
系統(tǒng)采用LogBack日志組件 ,在輸出日志時輸出_traceId日志跟蹤號,logback.xml配置如下 :
../log/${ ServerName}/${ AppName}.log ../log/${ ServerName}/${ AppName}.log.%d{ yyyy-MM-dd} 7 %d{ HH:mm:ss.SSS} %-5level [%.15thread][%X{ _traceId}] %logger{ 36} - %.-4096msg%n 公司系統(tǒng)采用分布式架構(gòu) ,從接收到請求到業(yè)務(wù)處理完成并返回,涉及SpringMVC入口 、服務(wù)間dubbo調(diào)用、基于RocketMQ實現(xiàn)的業(yè)務(wù)解耦、以及來自第三方渠道的http通知回調(diào)。
現(xiàn)在的問題是從業(yè)務(wù)請求入口到返回業(yè)務(wù)響應(yīng),如何使用同一traceId將日志做串聯(lián) ?
Slf4j的MDC機制提供了上述問題的解決方案。
二 、解決方案
在介紹具體解決方案之前,首先介紹下Slf4j日志框架的MDC機制。映射診斷上下文(Mapped Diagnostic Context ,簡稱MDC)可以簡單理解為當前日志線程的上下文,也是一個k-v格式的map結(jié)構(gòu) 。
當服務(wù)器幾乎同時處理多個請求時 ,日志輸出通常是交錯的,而MDC是基于每個線程進行管理的 ,子線程自動繼承其父線程的MDC的副本 ??梢酝ㄟ^往MDC里塞入traceId,達到串聯(lián)日志的目的。
以下為MDC填充獲取traceId方法 :
public final static String TRACE_ID = "_traceId";static private String generateTraceId() { return UUID.randomUUID().toString().replaceAll("-", "");}public static String getTraceId() { return MDC.get(TRACE_ID);}public static void setTraceId(String traceId) { MDC.put(TRACE_ID, traceId);}public static void clearTrace() { MDC.remove(TRACE_ID);}public static void initTrace() { String traceId = generateTraceId(); setTraceId(traceId);}