12

我试图在检票口中记录几个onBeginRequest()RequestCycle()。但是这些值没有记录在调试文件中。我将 MDC 中的值放入RequestCycleListeners().

以下是代码:

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”。

我已listener在扩展WebApplication.

我正在使用 log4j.xml,DEBUG appender它看起来如下:

<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>
4

2 回答 2

23

通常,仅当您通过配置在日志模式中包含 MDC 键时,MDC 值才会输出到日志。由于 slf4j 只是一个门面,因此您需要在 slf4j 下具有特定于框架的支持和配置才能使用 MDC。在此处阅读 slf4j 的注释。

因此,例如,如果您使用 log4j 作为 slf4j 下的 impl,那么您将需要 log4j 配置(ConversionPattern),例如:

%d %-5p [%c] [%X{serverName} %X{sessionId}] %m%n

%X{serverName} %X{sessionId}从 MDC 中提取值的相关部分在哪里。

是一个使用 log4j 而没有 sl4j 的非常好的示例。请在此处X查看log4j javadoc 中有关转换字符的注释。

请注意,logback 的模式语法是相同的。请在此处查看 logback 的详细信息。

另请注意,ThreadLocal当上下文不再在范围内时,MDC(使用底层)的最佳实践是清除上下文(删除您放入映射中的值)。这通常意味着调用removeclear在一个finally块中,例如:

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. 您的root记录器将记录到 3 个不同的附加程序,其中之一名为DEBUG,但它被配置为仅记录INFO级别和更高级别(基于priority标记),因此不会记录调试语句

除非您有一些未显示的单独配置的特定类别,否则我猜您的任何LOGGER.debug语句都不会被记录,无论您尝试使用 MDC。

于 2013-07-05T15:57:10.017 回答
0

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

不幸的是,在最新发布的 EOLed log4j-1.x 版本的 v 1.2.17中,AsyncAppender 的 Dispatcher-Thread 在停止时也不会清除 MDC。

由于 AsyncAppender/Dispatcher 相当简单,因此很容易通过放置

finally
{
    MDC.clear();
}

org.apache.log4j.AsyncAppender.Dispatcher.run()方法的 try-block 处。

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

于 2016-02-23T09:41:33.270 回答