无法将值放入MDC

12

我正在尝试在Wicket的RequestCycle()onBeginRequest()中记录一些值。 但是,这些值没有被记录在调试文件中。我将这些值放在RequestCycleListeners()中的MDC中。

以下是代码:

getRequestCycleListeners().add(new AbstractRequestCycleListener()
{       
public void onBeginRequest(RequestCycle cycle) 
{                   
  if( cycle.getRequest().getContainerRequest() instanceof HttpServletRequest )
  {
    HttpServletRequest containerRequest = 
        (HttpServletRequest)cycle.getRequest().getContainerRequest();

    MDC.put("serverName", containerRequest.getServerName());
    MDC.put("sessionId",  containerRequest.getSession().getId());

    LOGGER.debug("logging from RequestCycleListeners() !!!");
    WebClientInfo webClientInfo = new WebClientInfo(RequestCycle.get());
    System.out.println(webClientInfo.getUserAgent());
    System.out.println("webClientInfo.getProperties().getBrowserVersionMajor() " +containerRequest.getRemoteAddr());
}

};

我希望在调试文件中记录'serverName'和'sessionId'。

我已经在扩展'WebApplication'的类中添加了这个'listener'。

我正在使用log4j.xml,'DEBUG appender'如下所示:

<appender name="DEBUG" class="org.apache.log4j.RollingFileAppender">

<appender name="DEBUG" class="org.apache.log4j.rolling.RollingFileAppender">
  <param name="Append" value="true"/>
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="[%d{ISO8601} %t %5p] %m -- %X{serverName} -- %X{sessionId} -- %X{portNumber}%n"/>
  </layout>
  <filter class="org.apache.log4j.varia.LevelRangeFilter">
    <param name="LevelMin" value="DEBUG"/>
    <param name="LevelMax" value="WARN"/>
  </filter>
</appender>

我们正在根标签中定义作用域:

<root>
   <priority value="INFO" />
   <appender-ref ref="CONSOLE" />
   <appender-ref ref="DEBUG" />
   <appender-ref ref="ERROR" />
</root>

@Buurman:这是一种日志记录机制。您可以在此处查看更多信息:http://www.slf4j.org/api/org/slf4j/MDC.html。 - Ram Dutt Shukla
你在 slf4j 底层使用哪个日志框架?log4j、logback、java.util.logging 还是 commons logging? - superEb
@superEb: 目前使用log4j。 - Ram Dutt Shukla
@RamDuttShukla,您能否在问题中添加您的log4j配置和一些应用程序的日志记录示例?这可能会有所帮助。谢谢。 - Jonathan
@Jonathan:已添加log4j.xml配置文件。 - Ram Dutt Shukla
2个回答

24
通常情况下,只有在通过配置将MDC键包含在日志记录模式中时,MDC值才会输出到日志中。由于slf4j只是一个门面,您需要在slf4j下面拥有特定于框架的支持和配置才能使用MDC。请阅读slf4j关于此的说明here
例如,如果您正在使用log4j作为slf4j下面的实现,则需要像这样的log4j配置(ConversionPattern):
%d %-5p [%c] [%X{serverName} %X{sessionId}] %m%n

%X{serverName} %X{sessionId}是从MDC中获取值的相关部分。

这里有一个不错的log4j示例,没有使用sl4j。在log4j javadoc 这里查看关于X转换字符的注释。

请注意,logback的模式语法与之相同。在logback 这里查看具体内容。

还要注意,MDC的最佳实践(它在底层使用ThreadLocal)是在上下文不再在作用域内时清除上下文(删除放入映射中的值)。通常意味着在finally块中调用removeclear,例如:

try {
    //...
    MDC.put("key1", value1);
    MDC.put("key2", value2);
    //...
} finally {
    //this
    MDC.remove("key1");
    MDC.remove("key2");
    //or this
    MDC.clear();
}

这一点尤其重要,如果持有MDC的线程属于一个稍后重用的池。您肯定不希望无意中记录无效的上下文值,因为这只会导致混乱。
编辑
您的log4j配置似乎有些奇怪,原因如下:
1. 您将自己的附加器命名为日志级别,这可能会引起混淆 2. 您的RollingFileAppender未定义文件 3. 您的根记录器将记录到3个不同的附加器中,其中一个被命名为DEBUG,但它被配置为仅记录INFO级别及更高级别(基于priority标记),因此不会记录调试语句
除非您单独配置了一些未显示的特定类别,否则我猜测您的LOGGER.debug语句都没有被记录,无论您是否尝试使用MDC。

只是补充一下superEb的回答,logback手册中有关于如何使用MDC的说明http://logback.qos.ch/manual/mdc.html - Ravi Vasamsetty
我已经按照你在答案中提到的方法尝试了,参考了Veera-Sundar的博客,但问题似乎有所不同。 - Ram Dutt Shukla
我接受这个答案,因为解释非常有帮助。虽然它没有给出正确的答案,但它帮助我得到了答案。 - Ram Dutt Shukla
@RamDuttShukla - 我注意到您取消了我的答案。请查看我添加到EDIT部分的内容。它可能会帮助您解决日志问题。 - superEb
是的,未记录的原因是<root>标签。你是对的。现在我会再次接受这个答案,谢谢。 - Ram Dutt Shukla

0

请注意,如果您使用的是AsyncAppender,则从线程中清除MDC将无法保护您,因为日志事件和MDC处理发生在AsyncAppender的线程中。另请参见此相关错误

不幸的是,在最新发布的已停用的log4j-1.x版本v1.2.17中,AsyncAppender的调度线程在停止时也不会清除MDC。

由于AsyncAppender/Dispatcher相当简单,因此很容易通过添加补丁进行修复。

finally
{
    MDC.clear();
}

org.apache.log4j.AsyncAppender.Dispatcher.run() 方法的 try 块中。

当在 ServletContainer 中执行时,当然也可以通过不使用 AsyncAppender 来解决此问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接