13

Log4Jを使用するプロジェクトで作業しています。要件の 1 つは、スレッドごとに個別のログ ファイルを作成することです。これ自体は奇妙な問題であり、その場で新しい FileAppender を作成し、それを Logger インスタンスにアタッチすることによって、多少ソートされました。

Logger logger = Logger.getLogger(<thread dependent string>);
FileAppender appender = new FileAppender();
appender.setFile(fileName);
appender.setLayout(new PatternLayout(lp.getPattern()));
appender.setName(<thread dependent string>);
appender.setThreshold(Level.DEBUG);
appender.activateOptions();
logger.addAppender(appender);

私たちが使用する別のライブラリ - Spring Framework v3.0.0 ( Commons Loggingを使用) - が上記の手法でうまくいかないことに気付くまで、すべてがうまくいきました。ファイルではなく、ランタイムによって作成されたアペンダーによって。では、振り出しに戻ります。

調査の結果、新しく改善されたLogBackにはアペンダー(SiftingAppender) があることがわかりました。これは、独立したファイルでのスレッド レベルのログ記録など、必要なことを正確に実行します。

現時点では、LogBack への移行はオプションではないため、Log4J に固執している場合、SiftingAppender のような機能を実現し、Spring を満足させるにはどうすればよいでしょうか?

注: Spring はJdbcTemplate機能にのみ使用され、IOC には使用されません。Spring の Commons Logging を Log4J に「フック」するために、次の行を log4j.properties ファイルに追加しました。

log4j.logger.org.springframework=DEBUG

ここで指示されているとおり。

4

5 に答える 5

3

LogBack はslf4j apiを介してアクセスされます。jcl-over-sjf4jと呼ばれるアダプタ ライブラリがあり、コモンズ ロギング インターフェイスを公開しますが、すべてのロギングを slf4j API に行い、実装 - LogBack に直接送られます。Maven を使用している場合、依存関係は次のとおりです。

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.5.8</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>1.5.8</version>
</dependency> 
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>0.9.18</version>
</dependency>

(そして commons-logging を除外リストに追加します。ここを参照してください)

于 2009-12-20T16:03:28.633 に答える
3

私はしばらくの間、log4j で SiftingAppender のような機能を見つけるのに苦労しました (いくつかの依存関係のために logback に切り替えることができませんでした)。MDC を使用し、実行時にロガーを追加する、非常にうまく機能するプログラムによる解決策に行き着きました。

//  this can be any thread-specific string
String processID = request.getProcessID();  

Logger logger = Logger.getRootLogger();

//  append a new file logger if no logger exists for this tag
if(logger.getAppender(processID) == null){

  try{
    String pattern = "%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n";
    String logfile = "log/"+processID+".log";

    FileAppender fileAppender = new FileAppender(
        new PatternLayout(pattern), logfile, true);
    fileAppender.setName(processID);

    // add a filter so we can ignore any logs from other threads
    fileAppender.addFilter(new ProcessIDFilter(processID));

    logger.addAppender(fileAppender);
  }catch(Exception e){
    throw new RuntimeException(e);
  }
}

//  tag all child threads with this process-id so we can separate out log output
MDC.put("process-id", processID);

//whatever you want to do in the thread
LOG.info("This message will only end up in "+processID+".log!");

MDC.remove("process-id");

上に追加されたフィルターは、特定のプロセス ID をチェックするだけです。

public class RunIdFilter extends Filter {

  private final String runId;

  public RunIdFilter(String runId) {
    this.runId = runId;
  }

  @Override
  public int decide(LoggingEvent event) {
    Object mdc = event.getMDC("run-id");

    if (runId.equals(mdc)) {
      return Filter.ACCEPT;
    }

    return Filter.DENY;
  }
}

これが少し役立つことを願っています。

于 2013-06-18T19:34:33.433 に答える
0

私はすべての slf4j ファサード/リルーター/あなたがそれらを呼ぶものすべてを含めるのが好きです. また、「提供された」ハックにも注意してください。これにより、依存関係がコモンズのログに取り込まれなくなります。以前は、version-99.0-does-not-exist という偽の空のコモンズ ログ ライブラリを使用していました。

http://blog.springsource.com/2009/12/04/logging-dependencies-in-spring/も参照してください。

<dependencies>
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>

        <!-- use provided scope on real JCL instead -->
        <!-- <version>99.0-does-not-exist</version> -->

        <version>1.1.1</version>

        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging-api</artifactId>

        <!-- use provided scope on real JCL instead -->
        <!-- <version>99.0-does-not-exist</version> -->

        <version>1.1</version>

        <scope>provided</scope>
    </dependency>

    <!-- the slf4j commons-logging replacement -->
    <!-- if any package is using jakarta commons logging this will -->
    <!-- re-route it through slf4j. -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>

        <version>${version.slf4j}</version>
    </dependency>

    <!-- the slf4j log4j replacement. -->
    <!-- if any package is using log4j this will re-route -->
    <!-- it through slf4j. -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>log4j-over-slf4j</artifactId>

        <version>${version.slf4j}</version>
    </dependency>

    <!-- the slf4j java.util.logging replacement. -->
    <!-- if any package is using java.util.logging this will re-route -->
    <!-- it through slf4j. -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jul-to-slf4j</artifactId>
        <version>${version.slf4j}</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>

        <version>${version.slf4j}</version>
    </dependency>

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>

        <version>${version.logback}</version>
    </dependency>
</dependencies>

<properties>
    <version.logback>0.9.15</version.logback>
    <version.slf4j>1.5.8</version.slf4j>
</properties>
于 2009-12-22T08:10:11.823 に答える
0

log4j.NDC と MDC を見ましたか? これにより、少なくともスレッド固有のデータをログにタグ付けできます。あなたが求めているものとは正確には異なりますが、役に立つかもしれません。ここで議論があります。

于 2009-12-24T15:19:08.790 に答える