如何在微服务间传递Mapped Diagnostic Context(MDC),实现同一请求日志ID统一
跨微服务日志统一链路ID实现方案
核心逻辑就是把上游服务MDC里的链路ID通过请求头传给下游服务,下游服务拿到后放进自己的MDC,具体操作步骤如下:
1. 第一个服务(上游)处理流程
- 先通过过滤器/拦截器生成或获取链路ID,存入MDC:
// 第一个服务的请求过滤器 public class FirstServiceFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; // 优先从请求头拿链路ID,没有就生成新UUID String traceId = httpRequest.getHeader("X-Trace-ID"); if (traceId == null || traceId.isEmpty()) { traceId = UUID.randomUUID().toString(); } MDC.put("traceId", traceId); try { chain.doFilter(request, response); } finally { // 请求结束必须清理MDC,防止线程复用带旧数据 MDC.remove("traceId"); } } }
- 调用第二个服务时,把MDC里的traceId塞进请求头:
public void method() { String traceId = MDC.get("traceId"); // 构造请求头 HttpHeaders headers = new HttpHeaders(); headers.set("X-Trace-ID", traceId); HttpEntity<Void> entity = new HttpEntity<>(headers); // 调用下游服务 ResponseEntity<Data> response = restTemplate.exchange( "http://second-service/api/data", HttpMethod.GET, entity, Data.class ); Data data = response.getBody(); // 后续业务逻辑 }
2. 第二个服务(下游)处理流程
- 同样用过滤器拦截请求,从请求头拿traceId存入自身MDC:
// 第二个服务的请求过滤器 public class SecondServiceFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String traceId = httpRequest.getHeader("X-Trace-ID"); // 上游传了就用传的,没传就兜底生成新的 if (traceId == null || traceId.isEmpty()) { traceId = UUID.randomUUID().toString(); } MDC.put("traceId", traceId); try { chain.doFilter(request, response); } finally { MDC.remove("traceId"); } } }
3. 日志配置
两个服务的日志格式里要加上%X{traceId},比如logback配置:
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg traceId:%X{traceId}%n</pattern> </encoder> </appender>
额外优化
如果用Feign调用下游,不用每次手动加请求头,写个Feign拦截器统一处理:
public class FeignTraceIdInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate template) { String traceId = MDC.get("traceId"); if (traceId != null) { template.header("X-Trace-ID", traceId); } } }
内容的提问来源于stack exchange,提问作者Shubh
相关产品推荐
相关产品推荐

