web-dev-qa-db-ja.com

MDCに値を入力できません

改札の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>
12
Ram Dutt Shukla

通常、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 hereX変換文字に関する注記を参照してください。

ログバックのパターン構文は同じであることに注意してください。ログバックの詳細を参照してください ここ

また、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の構成は少し奇妙に思えます。

  1. ログレベルにちなんでアペンダーに名前を付けているため、混乱が生じる可能性があります
  2. RollingFileAppenderはファイルを定義していません
  3. rootロガーは3つの異なるアペンダーにログを記録します。そのうちの1つはDEBUGという名前ですが、(INFOタグに基づいて)priorityレベル以上のみをログに記録するように構成されているため、デバッグステートメントはログに記録されません。

表示されていない特定のカテゴリを個別に構成していない限り、LOGGER.debugステートメントのnoneは、関係なくログに記録されていると思います。 MDCを使用する試み。

21
superEb

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を使用しないことで、これを回避することもできます。

0
Jörg