Backend Development 9 min read

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.

Wukong Talks Architecture
Wukong Talks Architecture
Wukong Talks Architecture
Implementing End-to-End Log TraceId Tracing in Spring Cloud Microservices with MDC

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.

JavamicroservicesLogbackSpring CloudELKTraceIdMDC
Wukong Talks Architecture
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.