Log4j的NDC和MDC设施有什么区别?

时间:2013-01-03 07:29:44

标签: logging log4j

在Log4j中,NDC和MDC有什么区别?我可以用一个简单的例子来使用它们吗?

2 个答案:

答案 0 :(得分:28)

扩展Sikorski在评论中提出的link

NDC

在NDC中,N代表嵌套,这意味着您使用堆栈控制单个值。你“推”一个字符串,然后你可以在处理指令时“推”另一个字符串;处理完成后,您可以将其弹出以查看以前的值。这种上下文日志记录在一些深度嵌套的处理中很有用。

设置上下文字符串

NDC.push("processingLevel2"); 
log.info("success");

这将在日志中输出%x(小写)模式:

log4j.appender.CA.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSSS} %p %C %x = %m%n

MDC

M代表映射,这为您提供了不同类型的控件。您可以使用名称/值对,而不是使用单个堆栈来控制单个上下文字符串。这对于跟踪多个上下文位非常有用,例如将用户名和IP放入日志中。

设置映射值:

MDC.put("userIP", req.getRemoteAddr());
MDC.put("userName", foo.getName());
log.info("success");

示例MDC log4j模式

带有示例"userIP""userName"字符串的大写X.这些必须在您的代码和log4j配置中匹配:

log4j.appender.CA.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSSS} %p %X{userIP}  %C %X{userName} = %m%n

我将这些组合成一个)上下文字符串*。

相似点和不同点

在这两种情况下,无论何时执行log.info("success");,输出都将具有您提供的附加上下文。这比每次登录时连接log.info(req.getRemoteAddr()) + " success");这样的字符串要清晰得多。

请注意,两者在线程和资源方面存在严重差异。特别是,如果你不擅长弹出和清除NDC堆栈,NDC会保留你的线程句柄,这会影响资源的释放。

从链接:如果您不定期调用NDC.remove()方法,NDC使用可能会导致内存泄漏。

答案 1 :(得分:6)

MDC允许您为log4j添加自定义标记。例如:

%X{mytag} in log4j.xml

引用

MDC.put("mytag","StackOverflow");

MDC子线程自动继承其父级的映射诊断上下文的副本。

pushpopcleargetDepthsetMaxDepth等NDC操作仅影响当前线程的NDC。