Implement Logback MDC Request ID Tracing in Spring Boot

This guide explains how to integrate Logback with Spring Boot, use MDC to generate and propagate a requestId across services, and implement filters and Feign interceptors for end‑to‑end log traceability in microservice architectures.

Senior Brother's Insights
Senior Brother's Insights
Senior Brother's Insights
Implement Logback MDC Request ID Tracing in Spring Boot

Background

In monolithic applications a single log output is often enough, but once the system is split into multiple services and load‑balanced, the call chain becomes complex. In a microservice environment the number of possible request paths grows exponentially, making a unified log‑tracing mechanism essential for debugging.

Spring Boot + Logback Integration

Add the following Maven dependencies to enable Logback and bridge other logging APIs to SLF4J:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
</dependency>

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-to-slf4j</artifactId>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
</dependency>

Place a logback-spring.xml file under src/main/resources. Configure the console pattern to include a custom requestId stored in MDC:

<property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %contextName [%thread] %-5level [%X{requestId}] %logger{36} - %msg%n"/>

MDC Overview

MDC (Mapped Diagnostic Context) is a thread‑local map provided by SLF4J. It allows each thread to store diagnostic data such as a request identifier, which can later be referenced in log patterns via %X{key}. The core API consists of put, get, remove and clear. A simplified implementation used by Logback is shown below:

public class BasicMDCAdapter implements MDCAdapter {
    private InheritableThreadLocal<Map<String, String>> inheritableThreadLocal =
        new InheritableThreadLocal<Map<String, String>>() {
            @Override
            protected Map<String, String> childValue(Map<String, String> parentValue) {
                if (parentValue == null) {
                    return null;
                }
                return new HashMap<String, String>(parentValue);
            }
        };

    public void put(String key, String val) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }
        Map<String, String> map = inheritableThreadLocal.get();
        if (map == null) {
            map = new HashMap<>();
            inheritableThreadLocal.set(map);
        }
        map.put(key, val);
    }
    // get, remove, clear omitted for brevity
}

Implementation

Trace‑ID utilities

public class TraceIdUtils {
    /** Generate a 32‑character trace ID based on UUID */
    public static String getTraceId() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}
public class TraceIdContext {
    public static final String TRACE_ID_KEY = "requestId";

    public static void setTraceId(String traceId) {
        if (StringLocalUtil.isNotEmpty(traceId)) {
            MDC.put(TRACE_ID_KEY, traceId);
        }
    }

    public static String getTraceId() {
        String id = MDC.get(TRACE_ID_KEY);
        return id == null ? "" : id;
    }

    public static void removeTraceId() {
        MDC.remove(TRACE_ID_KEY);
    }

    public static void clearTraceId() {
        MDC.clear();
    }
}

When a thread pool is used, remember to call clearTraceId() after request processing to avoid leaking data to subsequent tasks.

Servlet filter for request entry

public class TraceIdRequestLoggingFilter extends AbstractRequestLoggingFilter {
    @Override
    protected void beforeRequest(HttpServletRequest request, String message) {
        String requestId = request.getHeader(TraceIdContext.TRACE_ID_KEY);
        if (StringLocalUtil.isNotEmpty(requestId)) {
            TraceIdContext.setTraceId(requestId);
        } else {
            TraceIdContext.setTraceId(TraceIdUtils.getTraceId());
        }
    }

    @Override
    protected void afterRequest(HttpServletRequest request, String message) {
        TraceIdContext.removeTraceId();
    }
}
@Configuration
public class TraceIdConfig {
    @Bean
    public TraceIdRequestLoggingFilter traceIdRequestLoggingFilter() {
        return new TraceIdRequestLoggingFilter();
    }
}

Feign interceptor for downstream calls (Spring Cloud OpenFeign)

@Configuration
public class FeignConfig implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header(TraceIdContext.TRACE_ID_KEY, TraceIdContext.getTraceId());
    }
}

Verification

After the above setup, a controller request produces logs that contain the same requestId across services, e.g.:

2021-04-13 10:58:31.092 cloud-service-consumer-demo [http-nio-7199-exec-1] INFO  [ef76526ca96242bc8e646cdef3ab31e6] c.b.demo.controller.CityController - getCity
2021-04-13 10:58:31.185 cloud-service-consumer-demo [http-nio-7199-exec-1] WARN  [ef76526ca96242bc8e646cdef3ab31e6] o.s.c.o.l.FeignBlockingLoadBalancerClient - ...

The identical requestId allows you to correlate all log entries belonging to the same request across the entire call chain.

Conclusion

When a request reaches the first service, the filter checks for an existing requestId. If absent, a new ID is generated and stored in MDC. Subsequent HTTP calls propagate the ID via the requestId header (Feign interceptor or manual header addition). Each service’s Logback configuration prints the ID, achieving end‑to‑end log correlation without external tracing frameworks.

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.

mdcspring-bootRequest ID
Senior Brother's Insights
Written by

Senior Brother's Insights

A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.

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.