Skip to main content

📘 Understanding MDC and NDC in Logging

When debugging production issues, logs are your best friends. But in multi-threaded applications or systems handling multiple requests, logs can quickly become messy and hard to trace. This is where MDC (Mapped Diagnostic Context) and NDC (Nested Diagnostic Context) come in.


🔹 What is MDC?

MDC (Mapped Diagnostic Context) allows you to store key-value pairs that are automatically added to your log entries.

👉 Example use case:

  • Storing userId, transactionId, or requestId in MDC so every log line contains this contextual information.

  • This makes tracing requests across distributed services much easier.

Code Example (SLF4J with Logback):

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class MDCExample {
    private static final Logger log = LoggerFactory.getLogger(MDCExample.class);

    public static void main(String[] args) {
        MDC.put("userId", "12345");
        MDC.put("transactionId", "txn-9876");

        log.info("Processing started");
        log.info("Processing in progress");

        MDC.clear(); // Always clear after use
    }
}

Sample Log Output:

2025-08-26 12:45:12 INFO  [userId=12345, transactionId=txn-9876] Processing started
2025-08-26 12:45:12 INFO  [userId=12345, transactionId=txn-9876] Processing in progress

🔹 What is NDC?

NDC (Nested Diagnostic Context) stores contextual information in a stack-like structure.

👉 Example use case:

  • If you want to track logs in a hierarchical process (e.g., request → method → sub-method), you can push and pop contexts.

Code Example:

import org.apache.log4j.Logger;
import org.apache.log4j.NDC;

public class NDCExample {
    private static final Logger log = Logger.getLogger(NDCExample.class);

    public static void main(String[] args) {
        NDC.push("User=12345");
        NDC.push("Order=9876");

        log.info("Starting order processing");
        
        NDC.pop(); // remove last
        log.info("Finished processing");

        NDC.remove(); // clear stack
    }
}

Sample Log Output:

2025-08-26 12:46:10 INFO  [User=12345 Order=9876] Starting order processing
2025-08-26 12:46:12 INFO  [User=12345] Finished processing

🔹 MDC vs NDC

Feature MDC (Mapped Diagnostic Context) NDC (Nested Diagnostic Context)
Data structure Key-Value Map Stack
Best for Adding metadata like userId, sessionId, transactionId Hierarchical trace (nested calls, sub-flows)
Usage Widely used in SLF4J & Logback Older Log4j concept
Thread-local Yes Yes

✅ Best Practices

  • Always clear MDC/NDC at the end of a request to prevent context leakage between threads.

  • Use MDC for distributed tracing (e.g., correlation IDs in microservices).

  • Use NDC only if you need nested contextual tracking (though MDC has largely replaced it in modern logging frameworks).


🔚 Conclusion

Both MDC and NDC help make logs more meaningful and traceable. In today’s distributed, microservice-driven world, MDC with correlation IDs is a must-have for debugging complex issues.


Comments

Popular posts from this blog

Understanding @Validated in Spring Boot: A Complete Guide

In real-world applications, we often deal with user input—whether it’s coming from APIs, forms, or service calls. Validating this input is critical to ensure our application behaves correctly and securely. Spring Boot makes this easier with annotations like @Valid and @Validated . In this blog, we’ll dive deep into what @Validated is, how it works, and when to use it —with examples you can apply directly to your projects. 📌 What is @Validated ? @Validated is a Spring Framework annotation ( org.springframework.validation.annotation.Validated ) that enables bean validation (JSR-303/JSR-380, powered by Hibernate Validator by default). It tells Spring to: Validate incoming request data (DTOs). Validate method arguments in services. Enforce constraints like @NotNull , @Email , @Size , etc. 📝 Example 1: Using @Validated in a REST Controller Suppose you have a REST endpoint to create a user: @RestController @RequestMapping("/api/users") public class UserController...