Slf4j运行时添加修改全局ID 实现微服务链路ID自动打印到日志
实现方案
你要的能力可以直接通过SLF4J原生提供的**MDC(映射诊断上下文)**实现,完全不需要切面拦截日志方法,性能和兼容性都更好,具体步骤如下:
步骤1:存入链路ID到MDC
你想要的Logger.setProps效果直接替换成MDC的API即可:
import org.slf4j.MDC; // 在REST Controller获取到pipelineId后调用 MDC.put("pipelineID", pipelineId);
注意:因为web服务的线程是池化复用的,必须在请求结束后清除MDC避免数据串用,建议通过Spring拦截器/Servlet过滤器统一处理,不需要每个Controller单独写存入逻辑:
@Component public class PipelineIdInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 直接从请求头/payload里提取pipelineId String pipelineId = request.getHeader("X-Pipeline-ID"); if (pipelineId != null) { MDC.put("pipelineID", pipelineId); } return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 请求结束清除MDC MDC.remove("pipelineID"); } }
SpringBoot项目只要实现WebMvcConfigurer的addInterceptors方法,把上面的拦截器注册进去就会全局生效。
步骤2:修改Logback配置输出MDC字段
你用的logback-contrib的JsonLayout本身就支持输出MDC内容,只需要在layout配置里加一行<includeMdc>true</includeMdc>即可:
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="ch.qos.logback.contrib.json.classic.JsonLayout"> <timestampFormat>yyyy-MM-dd'T'HH:mm:ss.SSSX</timestampFormat> <timestampFormatTimezoneId>UTC</timestampFormatTimezoneId> <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter"> <prettyPrint>false</prettyPrint> </jsonFormatter> <appendLineSeparator>true</appendLineSeparator> <!-- 新增下面这行,自动把所有MDC字段输出到JSON日志中 --> <includeMdc>true</includeMdc> </layout> </encoder>
改完之后你正常调用log.info("xxx"),输出的JSON日志里就会自动带上pipelineID: xxx的字段,完全符合你要的效果。
额外提示:你当前配置中的
log4j.rootLogger=INFO, DB, console是Log4j框架的配置,对Logback不生效,可以直接删除,Logback的根日志级别通过logback.xml中的<root level="INFO">配置即可。
扩展场景处理
- 如果有异步线程调用:需要配置线程池的
TaskDecorator,把父线程的MDC内容复制到子线程,避免异步日志丢失链路ID - 如果是跨微服务调用:调用下游服务时把pipelineID放到请求头里,下游服务同样通过拦截器提取存入MDC,就能实现全链路日志关联
内容的提问来源于stack exchange,提问作者MFEB
相关产品推荐
相关产品推荐

