java 无法将值放入 M​​DC

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16815602/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 00:03:53  来源:igfitidea点击:

not able to put the values in the MDC

javaloggingwicketmdc

提问by Ram Dutt Shukla

I am trying to log few values in the onBeginRequest()of RequestCycle()in wicket. But the values are not being logged in the debug file. I am putting the values in the MDC in RequestCycleListeners().

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

Following is the code:

以下是代码:

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());
}

};

};

I am expecting 'serverName', 'sessionId' to be logged in the debug file.

我希望在调试文件中记录“serverName”、“sessionId”。

I have added this listenerin the class which is extending the WebApplication.

listener在扩展WebApplication.

I am using log4j.xml the DEBUG appenderis looks as below:

我正在使用 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>

and we are defining scope in root tag :

我们在根标签中定义范围:

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

回答by superEb

Typically, MDC values are only output to logs if you include MDC keys in your logging pattern via configuration. Since slf4j is just a facade, you need to have framework-specific support and configuration underneath slf4j to make use of MDC. Read slf4j's notes on that here.

通常,如果您通过配置在日志记录模式中包含 MDC 键,则 MDC 值仅输出到日志。由于 slf4j 只是一个外观,您需要在 slf4j 下有特定于框架的支持和配置才能使用 MDC。在此处阅读 slf4j 对此的说明。

So, for example, if you're using log4j as the impl underneath slf4j, then you would need log4j config (ConversionPattern) like:

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

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

Where %X{serverName} %X{sessionId}is the relevant part that pulls values from the MDC.

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

Here's a pretty good example using log4j without sl4j. See notes on XConversion Character in log4j javadoc here.

是一个使用 log4j 而没有 sl4j 的很好的例子。请参阅此处有关Xlog4j javadoc 中的转换字符的注释。

Note that pattern syntax for logback is identical. See specifics for logback here.

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

Also note that best practice for MDC (which uses a ThreadLocalunder-the-hood) is to clear the context (remove the values you put in the map) when the context is no longer in scope. That typically means calling removeor clearin a finallyblock, like:

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

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

This is especially important if the thread that holds the MDC belongs to a pool for later reuse. You certainly don't want to unintentionally log invalid context values since that will just cause confusion.

如果持有 MDC 的线程属于一个池以供以后重用,这一点尤其重要。您当然不想无意中记录无效的上下文值,因为这只会引起混淆。

EDIT

编辑

Your log4j configuration seems a little odd, for the following reasons:

您的 log4j 配置似乎有点奇怪,原因如下:

  1. You are naming your appenders after log levels, which may cause confusion
  2. Your RollingFileAppenderdoes not define a file
  3. Your rootlogger will log to 3 different appenders, one of which is named DEBUG, but it is configured to only log INFOlevel and greater (based on the prioritytag), so debug statements will not be logged
  1. 您在日志级别后命名您的附加程序,这可能会导致混淆
  2. RollingFileAppender没有定义文件
  3. 您的root记录器将记录到 3 个不同的附加程序,其中一个名为DEBUG,但它被配置为仅记录INFO级别和更高(基于priority标签),因此不会记录调试语句

Unless you have some specific categories configured separately that are not shown, I would guess that noneof your LOGGER.debugstatements are being logged, regardless of your attempt to use MDC.

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

回答by J?rg

Note, that if you are using AsyncAppender, clearing MDCfrom your thread won't protect you, since the log event and MDC handling happens in the AsyncAppender's thread. See also this related bug

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

Unfortunately, in v1.2.17the latest released version of the EOLed log4j-1.x, the AsyncAppender's Dispatcher-Thread does not clear the MDC upon stopping either.

不幸的是,以V 1.2.17的EOLed的log4j-1.x的最新发布的版本中,AsyncAppender的分派线程不会在停止或者清除MDC。

Since, the AsyncAppender/Dispatcher is fairly simple, it's easy to patch it by putting

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

finally
{
    MDC.clear();
}

at the try-block in org.apache.log4j.AsyncAppender.Dispatcher.run()method.

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

Of course, one can also workaround this by not using AsyncAppender when executing in a ServletContainer.

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