改札の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>
通常、MDC値は、構成を介してログパターンにMDCキーを含めた場合にのみログに出力されます。 slf4jは単なるファサードであるため、MDCを使用するには、slf4jの下にフレームワーク固有のサポートと構成が必要です。それに関するslf4jのメモを読んでください ここ 。
したがって、たとえば、slf4jの下のimplとしてlog4jを使用している場合は、次のようなlog4j config(ConversionPattern)が必要になります。
%d %-5p [%c] [%X{serverName} %X{sessionId}] %m%n
ここで、%X{serverName} %X{sessionId}
は、MDCから値を取得する関連部分です。
ここ は、sl4jなしでlog4jを使用したかなり良い例です。 log4j javadoc here のX
変換文字に関する注記を参照してください。
ログバックのパターン構文は同じであることに注意してください。ログバックの詳細を参照してください ここ 。
また、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つの異なるアペンダーにログを記録します。そのうちの1つはDEBUG
という名前ですが、(INFO
タグに基づいて)priority
レベル以上のみをログに記録するように構成されているため、デバッグステートメントはログに記録されません。表示されていない特定のカテゴリを個別に構成していない限り、LOGGER.debug
ステートメントのnoneは、関係なくログに記録されていると思います。 MDCを使用する試み。
AsyncAppenderを使用している場合、スレッドから[〜#〜] mdc [〜#〜]をクリアすると 'ログイベントとMDC処理はAsyncAppenderのスレッドで発生するため、ユーザーを保護します。参照 この関連バグ
残念ながら、v1.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を使用しないことで、これを回避することもできます。