關注作者公眾號【互聯網專欄】獲取本項目源碼
SpringBoot中除了常見的分布式鏈路跟蹤系統zipkin、skywalking等,如果需要快速定位一次請求的所有日志,那么該如何實現?實際slf4j提供了MDC(Mapped Diagnostic Contexts)功能,支持用戶定義和修改日志的輸出格式以及內容。本文將介紹 Tracer集成的slf4j MDC功能,方便用戶在只簡單修改日志配置文件的前提下輸出當前 Tracer 上下文 TraceId。
MDC介紹
MDC(Mapped Diagnostic Context,映射調試上下文)是 log4j 、logback及log4j2 提供的一種方便在多線程條件下記錄日志的功能。MDC 可以看成是一個與當前線程綁定的哈希表,可以往其中添加鍵值對。MDC 中包含的內容可以被同一線程中執行的代碼所訪問。當前線程的子線程會繼承其父線程中的 MDC 的內容。當需要記錄日志時,只需要從 MDC 中獲取所需的信息即可。MDC 的內容則由程序在適當的時候保存進去。對於一個 Web 應用來說,通常是在請求被處理的最開始保存這些數據。
springboot中如何使用
添加攔截器
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String tid = UUID.randomUUID().toString().replace("-", "");
MDC.put(CloudConstant.MDC_TRACE, tid);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
MDC.remove(CloudConstant.MDC_TRACE);
}
}
注冊攔截器
@Configuration
public class WebInterceptorAdapter implements WebMvcConfigurer {
@Bean
public LogInterceptor logInterceptor() {
return new LogInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor());
}
}
修改日志輸出格式,添加%X{traceId},traceId和MDC中的鍵名稱一致
<pattern>%date %-5level ${PID:- } [%thread] [%X{tid}] : /*[%logger{50}:%line] %msg*/%n</pattern>
添加一個controller調用測試
@RestController
@RequestMapping("trace")
@Slf4j
public class TestTraceController {
@GetMapping("traceLog")
public String traceLog() {
log.info("---接口調用了---");
traceService();
return "success";
}
private void traceService(){
log.error("## 執行traceService方法");
}
}
日志打印如下,我們可以通過traceId快速查找出同一個請求的所有日志
細心的同學就會發現,MDC還是存在一些問題
- 在子線程中打印日志丟失traceId
- HTTP調用丟失traceId
在下一篇文章中小編繼續講解子線程中如何實現traceId的日志跟蹤