Logback / SLF4J File Appender多次写入日志条目

时间:2013-11-09 19:54:06

标签: java logging slf4j

我有一个用于日志记录的帮助程序类,它使用slf4j创建一个loggier并写入日志文件。

我正在使用FileAppender将日志写入已定义的文件。

问题是,这个FileAppender多次将每个日志行写入定义的文件中,但只在glassfish服务器的server.log中写入一次。

这就是我班级的样子:

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只被调用一次,在server.log中写入一个日志条目,但在给定的日志文件中写入多个日志条目。

感谢您的回答!

1 个答案:

答案 0 :(得分:3)

它会将de logline写入文件两次,因为在de LogBack配置中,文件已配置,然后再次将其添加到特定的Logger。由于日志框架在要写入的文件中是愚蠢的,因此它会将您的日志语句写两次。

查看代码,我看到您为每个logstatement创建了2次FileAppender。有点浪费记忆。如果程序发生某些事情导致它垃圾邮件日志文件,那么在Linux环境中可能会用完文件描述符。如果我是你,我应该放弃这个课程并直接从你的班级开始使用SLF4J。