Implement End-to-End Log Traceability in Spring Cloud Microservices with MDC

This article explains how to build a Spring Cloud‑based microservice framework and add full‑stack log traceability by generating a traceId, propagating it via MDC and interceptors, and visualizing the linked logs through ELK, covering both intra‑process and inter‑service scenarios.

ITPUB
ITPUB
ITPUB
Implement End-to-End Log Traceability in Spring Cloud Microservices with MDC

Background

We are constructing a basic project framework on top of Spring Cloud because the team cannot use external solutions such as Ruoyi and needs a custom, second‑generation framework that matches our specific requirements.

Core Features

Multiple microservice modules with a demo module for extension

Core framework module extraction

Eureka service registry

OpenFeign remote calls

Logback logging with traceId support

Swagger API documentation

Shared configuration files

ELK stack log search

Custom starter (planned)

Redis cache with Sentinel high availability

MySQL high‑availability setup

MyBatis‑Plus integration

Link tracing component (planned)

Monitoring (planned)

Utility classes (in development)

Gateway (technology selection pending)

Audit logs to Elasticsearch (planned)

Distributed file system (planned)

Scheduled tasks (planned)

Other features

Pain Points

1. In‑process log correlation

Multiple logs generated by different methods within a single request cannot be linked together.

Example: Method A logs entries 1 and 5, B logs entry 2, C logs entries 3 and 4, but there is no common identifier.

2. Cross‑service log correlation

Logs from different microservices (e.g., Order and Coupon services) are written to separate files and cannot be associated.

3. Cross‑thread log correlation

Logs generated by a parent thread and its child thread lack a common identifier.

4. Third‑party calls

Currently not addressed; will be considered later.

Solution Overview

We choose the MDC‑based approach because it introduces minimal middleware while still providing a workable traceability mechanism.

What is MDC?

MDC (Mapped Diagnostic Context) stores thread‑local contextual data, allowing each thread to attach a traceId that can be accessed by any logging code within that thread.

Implementation Steps

Add %X{traceId} to the Logback pattern:

<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 incoming HTTP header; if absent, generate a UUID and store it in 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 {
        MDC.remove("traceId"); // prevent memory leak
    }
}

Register the interceptor in Spring MVC configuration:

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Resource
    private LogInterceptor logInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(logInterceptor).addPathPatterns("/**");
    }
}

After this setup, every log entry automatically includes the same traceId, linking all logs belonging to the same request.

Cross‑service propagation

To keep the traceId across services, add an OpenFeign interceptor that copies the value from MDC into the outgoing 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 now log the same traceId, which can be searched in Elasticsearch via Kibana to reconstruct the full call chain.

Conclusion

By using an interceptor together with MDC, we inject a traceId into every log entry, enabling end‑to‑end tracing of both intra‑process method calls and inter‑service remote calls. Importing the logs into an ELK stack allows quick retrieval of the entire request flow via the shared traceId.

Future work includes extending the approach to cross‑thread tracing, third‑party calls, and adding dedicated monitoring components.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

loggingSpring CloudOpenFeignELKtraceidmdc
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

0 followers
Reader feedback

How this landed with the community

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.