简体   繁体   English

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

[英]Logback/SLF4J File Appender writes log entry multiple times

I'm having a helper class for logging, that creates a loggier with slf4j and writes the log file. 我有一个用于记录的帮助程序类,该类使用slf4j创建一个loggier并写入日志文件。

I'm using a FileAppender to write the log into a defined file. 我正在使用FileAppender将日志写入定义的文件中。

The problem is, that this FileAppender writes every log line multiple times into the defined file, but just one time in the server.log of the glassfish server. 问题在于,此FileAppender将每条日志行多次写入定义的文件,而在glassfish服务器的server.log中仅写入一次。

This is how my class looks like: 这是我的班级样子:

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);
    }
  }
}

I did some debug output to the console with System.out.println and eg .trace is only called once, writes one log entry in server.log but multiple ones in the given log file. 我使用System.out.println对控制台进行了一些调试输出,例如.trace仅被调用一次,在server.log中写入一个日志条目,但在给定的日志文件中写入多个日志条目。

Thanks for any answer! 感谢您的回答!

It will write de logline twice to the file, because in de LogBack configuration the file is configured and you add it again to the specific Logger. 它将两次在日志行中写入该文件,因为在LogBack配置中已配置了文件,然后将其再次添加到特定的Logger中。 And since log frameworks are dumb in which file to write to, it will write your log statement twice. 而且由于日志框架笨拙,无法写入哪个文件,因此它将两次写入您的日志语句。

Looking at the code, I see you create a FileAppender 2 times for each logstatement. 查看代码,我看到您为每个日志语句创建了2次FileAppender。 A bit of a waste of memory. 有点浪费内存。 And if something happens with the program which cause it to spam your log files, you might run out of file-descriptors on linux environments. 并且,如果该程序发生了某些事件,导致其将垃圾邮件发送到您的日志文件中,则您可能会在Linux环境中用尽文件描述符。 If I were you, I should ditch this class and start using SLF4J directly from your classes. 如果您是我,我应该放弃此类,直接从您的课堂开始使用SLF4J。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM