Implementing End-to-End Log TraceId Tracing in Spring Cloud Microservices with MDC
This article explains how to use MDC to generate and propagate a traceId across Spring Cloud microservices, configure Logback to output the traceId, and leverage ELK Stack for log aggregation, enabling comprehensive request‑level log tracing both within and across services.
Introduction
The author builds a basic project framework based on Spring Cloud microservices and decides to create a second‑generation framework rather than using off‑the‑shelf solutions due to project constraints.
Core Features
Multiple microservice modules with a demo module for extension
Core framework module, Eureka registration, OpenFeign remote calls
Logback with traceId, Swagger API docs, shared configuration, ELK log search
Redis high‑availability, MySQL high‑availability, MyBatis‑Plus integration
Custom starter, Redis sentinel, distributed file system, scheduled tasks (planned)
Pain Points
1. In‑process log correlation
Multiple logs generated by different methods in a single request cannot be linked together.
2. Cross‑service log correlation
Logs from separate microservices (e.g., order service and coupon service) are isolated and cannot be associated.
3. Cross‑thread log correlation
Logs from a parent thread and its child thread lack a common identifier.
4. Third‑party call tracing
Not addressed in the current implementation.
Solution Overview
1.1 Chosen Approach
Use the MDC (Mapped Diagnostic Context) method to generate a traceId, store it in MDC, and output it via Logback. This avoids adding heavy middleware in the early stage.
1.2 MDC Mechanism
MDC allows each thread to hold contextual data that can be accessed by any code running in that thread, making it suitable for propagating traceId.
Implementation Details
2.1 Tracing Multiple Logs Within a Single Request
Add %X{traceId} to the Logback pattern to print the traceId.
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %X{traceId} %-5level %logger - %msg%n</pattern>Create an interceptor that extracts traceId from the request header; if absent, generate a UUID and put it into MDC.
@Service
public class LogInterceptor extends HandlerInterceptorAdapter {
private static final String TRACE_ID = "traceId";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String traceId = request.getHeader(TRACE_ID);
if (StringUtils.isEmpty(traceId)) {
MDC.put("traceId", UUID.randomUUID().toString());
} else {
MDC.put(TRACE_ID, traceId);
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// Prevent memory leak
MDC.remove("traceId");
}
}Register the interceptor:
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Resource
private LogInterceptor logInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(logInterceptor).addPathPatterns("/**");
}
}When logging, the same traceId appears in all related log entries, enabling intra‑process tracing.
2.2 Cross‑Service Log Correlation
For remote calls (e.g., Order service calling Coupon service via OpenFeign), add a Feign interceptor that injects the current MDC traceId into the request header.
@Configuration
public class FeignInterceptor implements RequestInterceptor {
private static final String TRACE_ID = "traceId";
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header(TRACE_ID, (String) MDC.get(TRACE_ID));
}
}Both services log the same traceId, and after importing logs into Elasticsearch, Kibana can be used to search by traceId and reconstruct the full call chain.
Conclusion
By using an interceptor and MDC to inject a traceId into logs, developers can trace request flows across method calls, threads, and microservices. Combined with ELK Stack for log aggregation, the traceId enables end‑to‑end visibility of distributed transactions.
Wukong Talks Architecture
Explaining distributed systems and architecture through stories. Author of the "JVM Performance Tuning in Practice" column, open-source author of "Spring Cloud in Practice PassJava", and independently developed a PMP practice quiz mini-program.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.