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

DEBUG appender以下のように見える log4j.xml を使用しています。

<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 は単なるファサードであるため、MDC を利用するには、slf4j の下にフレームワーク固有のサポートと構成が必要です。ここで slf4j のメモを読んでください

たとえば、slf4j の下の impl として log4j を使用している場合、次のような log4j 構成 (ConversionPattern) が必要になります。

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

%X{serverName} %X{sessionId}MDC から値を取得する関連部分はどこにありますか。

これは、 sl4jなしで log4j を使用したかなり良い例です。ここXで、log4j javadoc の変換文字に関する注意事項を参照してください。

logback のパターン構文は同じであることに注意してください。logback の詳細については、こちらを参照してください。

また、MDC (内部を使用するThreadLocal) のベスト プラクティスは、コンテキストがスコープ外になったときにコンテキストをクリアする (マップに入力した値を削除する) ことです。これは通常、次のようにブロック内でremoveorを呼び出すことを意味します。clearfinally

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ログのみを記録するように構成されているため、デバッグ ステートメントはログに記録されません。INFOpriority

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

于 2013-07-05T15:57:10.017 に答える
0

AsyncAppenderを使用している場合、ログ イベントと MDC 処理は AsyncAppender のスレッドで発生するため、スレッドからMDCをクリアしても保護されないことに注意してください。この関連するバグも参照してください

残念ながら、サポートが終了した log4j-1.x の最新リリース バージョンである v 1.2.17では、AsyncAppender の Dispatcher-Thread が停止時に MDC をクリアしません。

AsyncAppender/Dispatcher はかなり単純なので、次のようにパッチを当てるのは簡単です。

finally
{
    MDC.clear();
}

org.apache.log4j.AsyncAppender.Dispatcher.run()メソッドの try ブロックで。

もちろん、ServletContainer で実行するときに AsyncAppender を使用しないことで、これを回避することもできます。

于 2016-02-23T09:41:33.270 に答える