Mastering SLF4J MDC for Precise Log Tracing in Multi‑Threaded Java Applications

This article explains how SLF4J’s Mapped Diagnostic Context (MDC) leverages ThreadLocal to embed trace and span identifiers into log messages, demonstrates configuring log4j2 patterns, shows code for injecting and clearing MDC values during span lifecycle, and addresses MDC propagation in asynchronous threads using Transmittable ThreadLocal.

ITFLY8 Architecture Home
ITFLY8 Architecture Home
ITFLY8 Architecture Home
Mastering SLF4J MDC for Precise Log Tracing in Multi‑Threaded Java Applications

If you often troubleshoot online issues, you may notice that log printing is usually unordered, and under multithreading it is like finding a needle in a haystack to serially obtain related logs for a single request. MDC provides an effective solution.

SLF4J's MDC

SLF4J offers the Mapped Diagnostic Context (MDC) feature, which is implemented using the ThreadLocal mechanism. In code, you simply put a specific value into the thread‑local map, and later retrieve it with the get method to customize the content of log output.

For example, a log4j2.xml template might contain:

<Pattern>%d %p [%c] [%X{key1},%X{key2}] - %m%n</Pattern>

In the log4j2.xml pattern, the %X{} placeholder is replaced with the corresponding MDC key value, enabling custom log formats.

MDC in Tracing

In a tracing framework, extending MDC is straightforward: insert the traceId and spanId in the span's before method, and clear them in the after method.

private void beforeStartSpan(Span span) {
    MDC.put(TraceKeys.TRACE_ID, span.getTraceId());
    MDC.put(TraceKeys.SPAN_ID, span.getSpanId());
}
private void afterEndSpan(Span span) {
    MDC.remove(TraceKeys.TRACE_ID);
    MDC.remove(TraceKeys.SPAN_ID);
    if (span != null) {
        MDC.put(TraceKeys.TRACE_ID, currentSpan.getTraceId());
        MDC.put(TraceKeys.SPAN_ID, currentSpan.getParentId()); // re‑insert parent span's spanId
    }
}

Then configure log4j2.xml as follows:

<Pattern>%d %p [%c] [%X{TraceId},%X{SpanId}] - %m%n</Pattern>  // add [%X{TraceId},%X{SpanId}] where appropriate

The resulting log output will look like:

2019-01-29 19:06:15,482 INFO [com.fredal.TestController] [e9b84d301f73f6e1a6386f216fa0120d,9296f83b058675d2] - this is a test in test
2019-01-29 19:06:15,489 INFO [com.fredal.TestController] [e9b84d301f73f6e1a6386f216fa0120d,f435c1cb819db821] - this is a test in test/provider

Because MDC is based on ThreadLocal, asynchronous logic cannot retrieve MDC values by default. However, our full‑link tracing framework has been adapted with Transmittable ThreadLocal, which propagates ThreadLocal objects across threads, allowing MDC values to be accessed in asynchronous threads as well.

Source: https://fredal.xin/mdc-in-tracing

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.

ThreadLocalslf4jlog4j2mdc
ITFLY8 Architecture Home
Written by

ITFLY8 Architecture Home

ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.

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.