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

sen*_*hil 23 logging log4j

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

Leo*_*ord 33

扩展Sikorski在评论中提到的链接:

NDC

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

设置上下文字符串

NDC.push("processingLevel2"); 
log.info("success");
Run Code Online (Sandbox Code Playgroud)

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

log4j.appender.CA.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSSS} %p %C %x = %m%n
Run Code Online (Sandbox Code Playgroud)

MDC

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

设置映射值:

MDC.put("userIP", req.getRemoteAddr());
MDC.put("userName", foo.getName());
log.info("success");
Run Code Online (Sandbox Code Playgroud)

示例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
Run Code Online (Sandbox Code Playgroud)

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

共同点和不同点

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

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

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

  • "......当处理完成后,您可以弹出它以查看前一个值." 这可能有点误导,因为每次你向NDC推送东西时,它会_appended_到已经存在的东西,当它被弹出时它会被删除.例如,如果NDC包含'foo'并且您按'bar',则日志输出将包括'foo bar',直到您弹出,之后它将仅包含'foo'.这是NDC有用的基础. (7认同)

S K*_* Kr 7

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

%X{mytag} in log4j.xml
Run Code Online (Sandbox Code Playgroud)

被引用

MDC.put("mytag","StackOverflow");
Run Code Online (Sandbox Code Playgroud)

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

NDC操作,例如push,pop,clear,getDepthsetMaxDepth只影响当前线程的NDC.