我正在尝试在wicket的onBeginRequest()
RequestCycle()
中记录少量值。
但是这些值未记录在调试文件中。我将值放在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'被记录在调试文件中。
我在扩展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标签中定义范围:
<root>
<priority value="INFO" />
<appender-ref ref="CONSOLE" />
<appender-ref ref="DEBUG" />
<appender-ref ref="ERROR" />
</root>
答案 0 :(得分:21)
通常,如果通过配置在日志记录模式中包含MDC密钥,则MDC值仅输出到日志。由于slf4j只是一个外观,您需要在slf4j下面具有特定于框架的支持和配置才能使用MDC。阅读slf4j关于here的注释。
所以,例如,如果你使用log4j作为slf4j下面的impl,那么你需要log4j config(ConversionPattern),如:
%d %-5p [%c] [%X{serverName} %X{sessionId}] %m%n
其中%X{serverName} %X{sessionId}
是从MDC中提取值的相关部分。
Here是使用没有sl4j的log4j的一个很好的例子。请参阅log4j javadoc here中X
转化字符的说明。
请注意,logback的模式语法是相同的。请参阅logback here的详细信息。
另请注意,MDC的最佳实践(使用ThreadLocal
引擎盖下)是在上下文不再在范围内时清除上下文(删除放在地图中的值)。这通常意味着在remove
块中调用clear
或finally
,例如:
try {
//...
MDC.put("key1", value1);
MDC.put("key2", value2);
//...
} finally {
//this
MDC.remove("key1");
MDC.remove("key2");
//or this
MDC.clear();
}
如果持有MDC的线程属于池以供以后重用,这一点尤其重要。您当然不希望无意中记录无效的上下文值,因为这只会引起混淆。
您的log4j配置似乎有点奇怪,原因如下:
RollingFileAppender
未定义文件root
记录器将记录到3个不同的appender,其中一个名为DEBUG
,但它配置为仅记录INFO
级别和更高级别(基于{{1标签),所以不会记录调试语句除非您单独配置了一些未显示的特定类别,否则我猜您的priority
语句的 none 正在被记录,无论您尝试使用MDC。
答案 1 :(得分:0)
请注意,如果您使用的是 AsyncAppender ,则从您的线程清除 MDC 将无法保护您,因为日志事件和MDC处理发生在AsyncAppender的线程中。另请参阅this related bug
不幸的是,在v 1.2.17 最新发布的EOLed log4j-1.x版本中,AsyncAppender的Dispatcher-Thread在停止时也没有清除MDC。
因为AsyncAppender / Dispatcher非常简单,所以很容易通过添加
来修补它finally
{
MDC.clear();
}
在 org.apache.log4j.AsyncAppender.Dispatcher.run()方法的try-block中。
当然,也可以通过在ServletContainer中执行时不使用AsyncAppender来解决此问题。