In Log4j, what is the difference between NDC and MDC? Can I have a simple example where they are used?
"MDC" stands for "Mapped Diagnostic Context". NDC has been part of the log4j framework longer than MDC. If you haven't already, you may want to review the javadoc information for each class.
Log4j2, Logback. Java Logging, MDC. A Mapped Diagnostic Context, or MDC in short, is an instrument for distinguishing interleaved log output from different sources. Log output is typically interleaved when a server handles multiple clients near-simultaneously.
The ThreadContext allows applications to store information either in a Map or a Stack. The MDC is managed on a per thread basis. To enable automatic inheritance of copies of the MDC to newly created threads, enable the "isThreadContextMapInheritable" Log4j system property.
A ThreadContext is a map of string headers and a transient map of keyed objects that are associated with a thread. It allows to store and retrieve header information across method calls, network calls as well as threads spawned from a thread that has a ThreadContext associated with.
Nested Diagnostic Context (NDC) is a mechanism to help distinguish interleaved log messages from different sources. NDC does this by providing the ability to add distinctive contextual information to each log entry. In this article, we will explore the use of NDC and its usage/support in various Java logging frameworks. 2. Diagnostic Contexts
MDC in Log4j Let's introduce MDC. MDC in Log4j allows us to fill a map-like structure with pieces of information that are accessible to the appender when the log message is actually written. The MDC structure is internally attached to the executing thread in the same way a ThreadLocal variable would be.
Nested Diagnostic Context (NDC) manages a stack of contextual information, on a per thread basis. The data in NDC is available to every log request in the code and can be configured to log with every log message – even at places where the data is not in scope.
MDC is available in SLF4J, too, under the condition that it is supported by the underlying logging library. Both Logback and Log4j support MDC as we've just seen, so we need nothing special to use it with a standard set up.
To expand on the link which Sikorski put in the comments:
In NDC, the N stands for nested, meaning you control a single value with a Stack. You "push" a string, then you can "push" another whenever processing dictates; and when processing is complete you can pop it off to see the former value. This sort of contextual logging would be useful in some deeply-nested processing.
NDC.push("processingLevel2"); log.info("success");
This will get output in your log where you have the %x
(lowercase) pattern:
log4j.appender.CA.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSSS} %p %C %x = %m%n
The M stands for mapped, and this gives you a different type of control. Instead of using a single stack to control a single contextual string, you use name/value pairs. This is useful for tracking multiple contextual bits, such as putting username and IP into the log.
MDC.put("userIP", req.getRemoteAddr()); MDC.put("userName", foo.getName()); log.info("success");
Uppercase X with the example "userIP"
and "userName"
strings. These must match in your code and in the log4j config:
log4j.appender.CA.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSSS} %p %X{userIP} %C %X{userName} = %m%n
I would combine these into one )context string*.
In both cases, whenever you do the log.info("success");
, the output will have the additional context you have provided. This is much cleaner than concatenating strings like log.info(req.getRemoteAddr()) + " success");
every time you log.
Note that there are serious differences between the two with respect to threading and resources. In particular, NDC will keep handles to your threads which can affect the freeing of resources if you are not diligent about popping and clearing the NDC stack.
From the link: NDC use can lead to memory leaks if you do not periodically call the NDC.remove()
method.
MDC allows you to add custom tags for log4j. eg:
%X{mytag} in log4j.xml
is referenced by
MDC.put("mytag","StackOverflow");
MDC child thread automatically inherits a copy of the mapped diagnostic context of its parent.
NDC operations such as push
, pop
, clear
, getDepth
and setMaxDepth
affect the NDC of the current thread only.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With