java xml 94 lines · 4 tabs

Propagate a Correlation ID Through Every Log Line with an MDC Servlet Filter in Spring Boot

Shared by codesnips Aug 2026
4 tabs
package com.example.observability;

public final class CorrelationIdConstants {

    public static final String HEADER_NAME = "X-Correlation-Id";
    public static final String MDC_KEY = "correlationId";

    private CorrelationIdConstants() {
    }
}
4 files · java, xml Explain with highlit

This snippet shows how a single request-scoped identifier can be attached to every log line produced while handling an HTTP request, so that logs from many concurrent requests can be untangled after the fact. The technique relies on SLF4J's MDC (Mapped Diagnostic Context), a thread-local map whose entries the logging framework can interpolate into each line via a pattern token.

In CorrelationIdFilter, an OncePerRequestFilter runs at the very start of the servlet chain. It reads an incoming X-Correlation-Id header if the caller already supplied one (useful when an upstream service or gateway started the trace), and otherwise mints a fresh UUID. The value is placed into MDC under the key correlationId and echoed back on the response so clients can capture it. The try/finally is the critical detail: because MDC is backed by a thread-local, failing to call MDC.remove would leak the id onto the next request that reuses the same pooled worker thread, producing subtly wrong logs. Ordering the filter with @Order(HIGHEST_PRECEDENCE) ensures the context is set before any downstream filter, controller, or exception handler logs anything.

The CorrelationIdConstants tab centralises the header name and MDC key so the filter, the client wrapper, and tests never drift apart on string literals. CorrelationContext exposes a tiny read accessor so application code can retrieve the current id without depending on SLF4J directly.

To keep the trace intact across service boundaries, TracingWebClientConfig registers an ExchangeFilterFunction on a WebClient. Before each outbound call it reads the current id from MDC and copies it into the outbound request's headers, so the downstream service's own filter can pick it up and continue the same trace.

The logback-spring.xml tab wires everything together by adding [%X{correlationId}] to the console pattern; %X{...} is Logback's syntax for pulling a named value out of the MDC. A key pitfall this pattern does not solve on its own is asynchronous work: when a request hands off to a @Async method or a manually managed thread pool, the MDC does not propagate automatically and must be copied explicitly or wrapped with a task decorator. For plain synchronous request handling, however, this filter-based approach adds structured, greppable context to every log line at almost zero cost.


Related snips

Share this code

Here's the card — post it anywhere.

Propagate a Correlation ID Through Every Log Line with an MDC Servlet Filter in Spring Boot — share card
Link copied