0

slf4j でロガーを作成し、ログ ファイルを書き込むログ用のヘルパー クラスがあります。

FileAppender を使用して、ログを定義済みファイルに書き込みます。

問題は、この FileAppender がすべてのログ行を定義済みファイルに複数回書き込みますが、glassfish サーバーの server.log には 1 回だけ書き込むことです。

これは私のクラスがどのように見えるかです:

package de.mycompany.framework.jframework.logging;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.FileAppender;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.slf4j.LoggerFactory;

/**
 * Logger
 * @author Marc Vollmer
 */
public class Logger {
  /**
   * Log Level
   * Default: OFF
   */
  private Level level = Level.OFF;

  /**
   * Constructor
   */
  public Logger() {
    String sLogLevel = "OFF";
    try {
      sLogLevel = (String)new InitialContext().lookup("jfw/LogLevel");
    } catch (NamingException ex) {

    }
    switch(sLogLevel.toUpperCase()) {
      case "DEBUG":
        level = Level.DEBUG;
        break;
      case "INFO":
        level = Level.INFO;
        break;
      case "TRACE":
        level = Level.TRACE;
        break;
      case "WARN":
        level = Level.WARN;
        break;
      case "ERROR":
        level = Level.ERROR;
        break;
      case "ALL":
        level = Level.ALL;
        break;
      default:
        level = Level.OFF;
        break;
    }
  }

  /**
   * Set the Log Level
   * 
   * @param level Log Level
   */
  public void setLevel(Level level) {
    this.level = level;
  }

  /**
   * Get the Log Level
   * 
   * @return Log Level
   */
  public Level getLevel() {
    return level;
  }

  /**
   * Get Classname from Package Path
   * 
   * @param sPackage Package Path
   * @return Class name
   */
  private String getClassFromPackage(String sPackage) {
    if (sPackage.contains(".")) {
      return sPackage.split("\\.")[(sPackage.split("\\.").length-1)];
    } else {
      return sPackage;
    }
  }

  /**
   * Is the class ignored?
   * 
   * @param sPackString Package PAth
   * @return true if ignored, false if not
   */
  private boolean isIgnoredClass(String sPackString) {
    switch (getClassFromPackage(sPackString)) {
      case "Logger":
      case "Thread":
        return true;
      default:
        return false;
    }
  }

  /**
   * Get the Logger
   * 
   * @return SLF4J Logger
   */
  private org.slf4j.Logger getLogger() {
    String sName;
    StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
    int i = 0;
    StackTraceElement e = stacktrace[i]; // TODO: Adjust after tests
    while (isIgnoredClass(e.getClassName())) {
      e = stacktrace[++i];
    }
    sName = getClassFromPackage(e.getClassName()) + "." + e.getMethodName();
    LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
    ch.qos.logback.classic.Logger logger = lc.getLogger(sName);
    logger.addAppender(getFileAppender(lc));
    logger.setLevel(level);
    return logger;
  }

  /**
   * Create a file appender
   * 
   * @param lc Logger Context
   * @return File Appender
   */
  private FileAppender<ILoggingEvent> getFileAppender(LoggerContext lc) {
    FileAppender<ILoggingEvent> fa = new FileAppender<>();
    fa.setContext(lc);
    fa.setName("FILE");
    try {
      fa.setFile((String)new InitialContext().lookup("jfw/LogFile"));
    } catch (NamingException ex) {
      fa.setFile("../logs/jfw.log");
    }
    PatternLayoutEncoder pl = new PatternLayoutEncoder();
    pl.setContext(lc);
    try {
      pl.setPattern((String)new InitialContext().lookup("jfw/LogPattern"));
    } catch (NamingException ex) {
      pl.setPattern("%d{dd.MM.yyyy HH:mm:ss.SSS} [%-5(%level)] [%-50.50(%C{0}.%M)] %m%n%xEx");
    }
    pl.start();
    fa.setEncoder(pl);
    fa.start();
    return fa;
  }

  /**
   * Trace Message
   * 
   * @param sMsg Log Message
   */
  public void trace(String sMsg) {
    if (getLogger().isTraceEnabled()) {
      getLogger().trace(sMsg);
    }
  }

  /**
   * Trace Message
   * 
   * @param sMsg Log Message
   * @param throwable Throwable
   */
  public void trace(String sMsg, Throwable throwable) {
    if (getLogger().isTraceEnabled()) {
      getLogger().trace(sMsg, throwable);
    }
  }

  /**
   * Debug Message
   * 
   * @param sMsg Log Message
   */
  public void debug(String sMsg) {
    if (getLogger().isDebugEnabled()) {
      getLogger().debug(sMsg);
    }
  }

  /**
   * Debug Message
   * 
   * @param sMsg Log Message
   * @param throwable Throwable
   */
  public void debug(String sMsg, Throwable throwable) {
    if (getLogger().isDebugEnabled()) {
      getLogger().debug(sMsg, throwable);
    }
  }

  /**
   * Info Message
   * 
   * @param sMsg Log Message
   */
  public void info(String sMsg) {
    if (getLogger().isInfoEnabled()) {
      getLogger().info(sMsg);
    }
  }

  /**
   * Info Message
   * 
   * @param sMsg Log Message
   * @param throwable Throwable
   */
  public void info(String sMsg, Throwable throwable) {
    if (getLogger().isInfoEnabled()) {
      getLogger().info(sMsg, throwable);
    }
  }

  /**
   * Warn Message
   * 
   * @param sMsg Log Message
   */
  public void warn(String sMsg) {
    if (getLogger().isWarnEnabled()) {
      getLogger().warn(sMsg);
    }
  }

  /**
   * Warn Message
   * 
   * @param sMsg Log Message
   * @param throwable Throwable
   */
  public void warn(String sMsg, Throwable throwable) {
    if (getLogger().isWarnEnabled()) {
      getLogger().warn(sMsg, throwable);
    }
  }

  /**
   * Error Message
   * 
   * @param sMsg Log Message
   */
  public void error(String sMsg) {
    if (getLogger().isErrorEnabled()) {
      getLogger().error(sMsg);
    }
  }

  /**
   * Error Message
   * 
   * @param sMsg Log Message
   * @param throwable Throwable
   */
  public void error(String sMsg, Throwable throwable) {
    if (getLogger().isErrorEnabled()) {
      getLogger().error(sMsg, throwable);
    }
  }
}

System.out.println を使用してコンソールにデバッグ出力を行いました。たとえば、.trace は 1 回だけ呼び出され、server.log には 1 つのログ エントリが書き込まれますが、指定されたログ ファイルには複数のログ エントリが書き込まれます。

答えてくれてありがとう!

4

1 に答える 1

3

LogBack 構成でファイルが構成され、特定の Logger に再度追加するため、ログラインがファイルに 2 回書き込まれます。また、ログ フレームワークはどのファイルに書き込むかが難しいため、ログ ステートメントを 2 回書き込みます。

コードを見ると、ログステートメントごとに FileAppender を 2 回作成していることがわかります。メモリの少し無駄。また、ログ ファイルをスパムする原因となる何かがプログラムで発生した場合、Linux 環境ではファイル記述子が不足する可能性があります。もし私があなたなら、このクラスを捨てて、あなたのクラスから直接 SLF4J を使い始める必要があります。

于 2013-11-09T20:05:14.813 に答える