You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在微服务间传递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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 12:40:24