質問

Quartzベースの全体的なスケジューラと<!> quot; CycledJob <!> quot;で構成されるアプリケーションに取り組んでいます。 CronTriggersを使用して実行します。このアプリケーションの目的は、ソース国に基づいてさまざまなメール受信ボックスからの入力を処理することです。

入国した国(米国、英国、FRなど)に基づいて、アプリケーションは1つのジョブスレッドをトリガーして、各国の処理サイクルを実行します。したがって、英国、米国、フランスのワーカースレッドがあります。出力をlog4jにフォーマットするとき、threadパラメーターを使用しているため、[ApplicationName_Worker-1]、[ApplicationName_Worker-2]などを出力します。できる限り試してみて、スレッドに名前を付ける方法が見つかりませんQuartzのスレッドプールから引き出されるためです。 Quartzを拡張することもできますが、標準ライブラリをいじるのではなく、別のソリューションを作成したいと思います。

ここに問題があります。log4jを使用する場合、米国のスレッドからのすべてのログ項目を、米国のスレッドごとに、米国のみのファイルに出力したいと思います。それらが1つの統合されたConsoleAppenderにとどまるかどうかは気にしません。FileAppenderの分割は、私がここで求めているものです。複数のファイルアペンダーを指定する方法などは既に知っていますが、私の問題は国に基づいて区別できないことです。アプリケーションには20以上のクラスがあり、それらは実行チェーン上にある可能性がありますが、余分な<!> quot; context <!> quot;すべてのメソッドを介したパラメーター... log4jラッパークラスを拡張する戦略パターンを検討しましたが、チェーン内のすべてのクラスにロガー呼び出しをパラメーター化するスレッドを知らせることができない限り、それは不可能に思えます。スレッドに名前を付けることができないと、チャレンジも作成されます(そうでなければ簡単になります!)。

質問は次のとおりです。アプリケーションの多くの下位クラスがそれぞれ異なるスレッドに使用され、入力を処理できるようにするための推奨されるアプローチは、ロギング中に特定の国のスレッドのコンテキスト内にあることを知ることです

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

役に立ちましたか?

解決

各国の処理スレッドの上部で、国コードを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);
  }
}
...

カスタムフィルター:

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> 

他のヒント

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

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

  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 logger = Logger.getLogger(<!> quot; my-us-logger <!> quot;);

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

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

log4j.additivity.my-us-logger=false
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top