4

全体的な Quartz ベースのスケジューラと CronTriggers を使用して実行される「CycledJob」で構成されるアプリケーションに取り組んでいます。アプリケーションの目的は、送信元の国に基づいて、さまざまな電子メールの受信トレイからの入力を処理することです。

送信元の国 (米国、英国、フランスなど) に基づいて、アプリケーションは 1 つのジョブ スレッドをトリガーして各国の処理サイクルを実行します。そのため、英国のワーカー スレッド、米国、フランスなどに 1 つのスレッドが存在します。出力を log4j にフォーマットするとき、スレッド パラメーターを使用しているため、[ApplicationName_Worker-1]、[ApplicationName_Worker-2] などを発行します。 Quartz のスレッドプールから引き出されました。Quartz を拡張することもできますが、標準ライブラリをいじるのではなく、別の解決策を考えたいと思います。

問題は次のとおりです。log4j を使用する場合、米国のスレッドのすべてのログ項目を米国のみのファイルに出力したいと考えています。同様に、各国のスレッドについても同様です。それらが 1 つの統合された ConsoleAppender にとどまっているかどうかは気にしません。FileAppender の分割は、私がここで求めているものです。複数のファイルアペンダーなどを指定する方法はすでに知っていますが、国によって区別できないという問題があります。アプリケーション内には実行チェーン上に存在する可能性のある 20 以上のクラスがありますが、すべてのメソッドを介して追加の「コンテキスト」パラメーターを渡すという知識を負担にしたいクラスはほとんどありません... log4j ラッパー クラスを使用していますが、ロガー呼び出しをパラメーター化するスレッドをチェーン内のすべてのクラスに知らせることができない限り、それは不可能に思えます。

では、ここで質問があります。アプリケーション内のさまざまなスレッドごとに入力を処理するために使用される多くの下位クラスが、ログを記録しているときに特定の国のスレッドのコンテキスト内にあることを認識できるようにするための推奨されるアプローチは何でしょうか?

よく理解してください。明確な質問をしてください。誰かがこれに取り組むための適切な方法を見つけるのを手伝ってくれることを願っています. すべての提案を歓迎します。

4

4 に答える 4

5

各国の処理スレッドの先頭で、国コードを Log4j のマップされた診断コンテキスト (MDC) に入れます。これは ThreadLocal 変数を使用するため、コール スタックを明示的に上下に国を渡す必要はありません。次に、MDC を参照するカスタム フィルターを作成し、現在のアペンダーの国コードを含まないイベントを除外します。

あなたのJob

...
public static final String MDC_COUNTRY = "com.y.foo.Country";
public void execute(JobExecutionContext context)
  /* Just guessing that you have the country in your JobContext. */
  MDC.put(MDC_COUNTRY, context.get(MDC_COUNTRY));
  try {
    /* Perform your job here. */
    ...
  } finally {
    MDC.remove(MDC_COUNTRY);
  }
}
...

カスタムFilterを作成します。

package com.y.log4j;

import org.apache.log4j.spi.LoggingEvent;

/**
 * This is a general purpose filter. If its "value" property is null, 
 * it requires only that the specified key be set in the MDC. If its 
 * value is not null, it further requires that the value in the MDC 
 * is equal.
 */
public final class ContextFilter extends org.apache.log4j.spi.Filter {

  public int decide(LoggingEvent event) {
    Object ctx = event.getMDC(key);
    if (value == null)
      return (ctx != null) ? NEUTRAL : DENY;
    else
      return value.equals(ctx) ? NEUTRAL : DENY;
  }

  private String key;
  private String value;

  public void setContextKey(String key) { this.key = key; }
  public String getContextKey() { return key; }
  public void setValue(String value) { this.value = value; }
  public String getValue() { return value; }

}

log4j.xml で:

<appender name="fr" class="org.apache.log4j.FileAppender">
  <param name="file" value="france.log"/>
  ...
  <filter class="com.y.log4j.ContextFilter">
    <param name="key" value="com.y.foo.Country" />
    <param name="value" value="fr" />
  </filter>
</appender> 
于 2008-09-27T18:21:14.677 に答える
2

これよりも少しお役に立てれば幸いですが、いくつかのフィルターを使用して調査することをお勧めします。おそらく、ロギングによって国コードが出力され、それに基づいてフィルターを一致させることができるでしょうか?

StringMatchFilter は、おそらくそれを一致させることができるはずです。

以下のアドレスをリンクとして正しく機能させることができませんでしたが、それを見ると、フィルターを使用した個別のファイル ロギングに関する情報が含まれています。

http://mail-archives.apache.org/mod_mbox/logging-log4j-user/200512.mbox/ <1CC26C83B6E5AA49A9540FAC8D35158B01E2968E@pune.kaleconsultants.com > (> の前のスペースを削除するだけです)

http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/spi/Filter.html

于 2008-09-27T03:46:52.797 に答える
1

ジョブがスレッドの名前を設定し始めたときに、Thread.setName()を呼び出してみませんか?アクセスに問題がある場合は、独自のスレッドプールを使用するようにquartzを構成します。

于 2008-09-27T20:45:23.253 に答える
1

私はあなたが何を達成しようとしているのかについての私の理解に完全に基づいていないかもしれませんが、私は解決策を突き刺します。メールを処理している国ごとに個別のログファイルが必要なようです。その理解に基づいて、考えられる解決策は次のとおりです。

  1. 個別にログを記録する国ごとに、log4j構成にアペンダーを設定します(米国の例を提供)。

    log4j.appender.usfile = org.apache.log4j.FileAppender

    log4j.appender.usfile.File = us.log

    log4j.appender.usfile.layout = org.apache.log4j.PatternLayout

    log4j.appender.usfile.layout.ConversionPattern =%m%n

  2. 国ごとにロガーを作成し、それぞれを適切なアペンダーに誘導します(米国の例を提供)。

    log4j.logger.my-us-logger = debug、usfile

  3. コードで、メールが処理されている国に基づいてロガーを作成します。

    ロガーロガー=Logger.getLogger( "my-us-logger");

  4. 後続のメソッド呼び出しのためにステップ3をどのように実行するかを決定します。各クラス/メソッドでステップ3を繰り返すことができます。または、メソッドシグネチャを変更して、ロガーを入力として受け入れることができます。または、 ThreadLocalを使用して、メソッド間でロガーを渡すこともできます。

追加情報:ログステートメントが親ロガー(rootLoggerなど)に送信されないようにする場合は、それらの加法性フラグをfalseに設定できます(米国の例を提供)。

log4j.additivity.my-us-logger=false
于 2008-09-27T04:48:59.497 に答える