【问题标题】:Setting Logback Appender path programmatically以编程方式设置 Logback Appender 路径
【发布时间】:2011-04-17 17:17:26
【问题描述】:

我正在尝试以编程方式设置 Logback 附加程序路径。 (RollingFileAppender 确切地说是 FixedWindowRollingPolicy)

我这样做是因为我想让我的用户在首选项对话框 (Eclipse RCP) 中设置日志路径

我已经尝试过这样的事情,但我没有更改配置文件中定义的日志路径:

Logger logback_logger = (ch.qos.logback.classic.Logger)LoggerFactory
   .getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
RollingFileAppender<ILoggingEvent> rfappender = 
   (RollingFileAppender<ILoggingEvent>)logback_logger.getAppender("FILE");
rfappender.setFile(newFile);
FixedWindowRollingPolicy rollingPolicy = 
   (FixedWindowRollingPolicy)rfappender.getRollingPolicy();
rollingPolicy.setFileNamePattern(newPattern);

【问题讨论】:

    标签: java logging logback


    【解决方案1】:

    以编程方式配置附加程序后,您需要调用其start() 方法。如果 appender 有子组件,请先在子组件上调用 start()。然后将 appender 添加到您选择的记录器中。

    这是一个例子:

    import ch.qos.logback.classic.Logger;
    import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
    import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
    import ch.qos.logback.core.rolling.RollingFileAppender;
    import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
    import ch.qos.logback.core.util.StatusPrinter;
    import org.slf4j.LoggerFactory;
    import ch.qos.logback.classic.LoggerContext;
    
    public class Main {
      public static void main(String[] args) {
        LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    
        RollingFileAppender rfAppender = new RollingFileAppender();
        rfAppender.setContext(loggerContext);
        rfAppender.setFile("testFile.log");
        FixedWindowRollingPolicy rollingPolicy = new FixedWindowRollingPolicy();
        rollingPolicy.setContext(loggerContext);
        // rolling policies need to know their parent
        // it's one of the rare cases, where a sub-component knows about its parent
        rollingPolicy.setParent(rfAppender);
        rollingPolicy.setFileNamePattern("testFile.%i.log.zip");
        rollingPolicy.start();
    
        SizeBasedTriggeringPolicy triggeringPolicy = new ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy();
        triggeringPolicy.setMaxFileSize("5MB");
        triggeringPolicy.start();
    
        PatternLayoutEncoder encoder = new PatternLayoutEncoder();
        encoder.setContext(loggerContext);
        encoder.setPattern("%-4relative [%thread] %-5level %logger{35} - %msg%n");
        encoder.start();
    
        rfAppender.setEncoder(encoder);
        rfAppender.setRollingPolicy(rollingPolicy);
        rfAppender.setTriggeringPolicy(triggeringPolicy);
    
        rfAppender.start();
    
        // attach the rolling file appender to the logger of your choice
        Logger logbackLogger = loggerContext.getLogger("Main");
        logbackLogger.addAppender(rfAppender);
    
        // OPTIONAL: print logback internal status messages
        StatusPrinter.print(loggerContext);
    
        // log something
        logbackLogger.debug("hello");
      }
    }
    

    上面的代码是 logback 的 XML 配置器(即 Joran)在解析 RollingFixedWindow.xml 文件时所采取的步骤的编程表达式。

    【讨论】:

    • (在记录东西上不同意你的观点有点尴尬,但是)这不是我想要做的——我想用 XML 配置我的记录器,并且只通过代码更改位置。这样,高级用户可以控制细粒度的日志记录属性,而新手用户可以使用 UI。通过代码重新启动appender;使用系统属性和 ContextInitializer 效果更好,硬编码更少,为什么这是不正确的?
    • 这种方法在最近发布的 Logback 中仍然有效吗?
    • RollingFixedWindow.xml 的链接已损坏
    • 链接已修复。谢谢。是的,一般方法对最新版本的 logback 仍然有效。
    • 链接又被破坏了。
    【解决方案2】:

    使用系统属性并重新加载配置文件似乎更干净:

    更改 logback.xml 文件:

    <file>${log_path:-}myfile.log</file>
    ....
    <FileNamePattern>${log_path:-}myfile.%i.log</FileNamePattern>
    

    这会将默认位置设置为工作目录。 然后,使用:

    System.setProperty("log_path", my_log_path);
    
    //Reload:
    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    ContextInitializer ci = new ContextInitializer(lc);
    lc.reset();
    try {
      //I prefer autoConfig() over JoranConfigurator.doConfigure() so I wouldn't need to find the file myself.
      ci.autoConfig(); 
    } catch (JoranException e) {
      // StatusPrinter will try to log this
      e.printStackTrace();
    }
    StatusPrinter.printInCaseOfErrorsOrWarnings(lc);
    

    【讨论】:

    • 使用 ContextInitializer 是非常不正确的。请参阅我的答案以了解正确的方法。
    • 很酷的东西!我改变了一件事:我使用 lc.putProperty("log_path", my_log_path) 而不是 System.setProperty。由于使用了 0 个全局变量,它看起来更好。
    • 这比以前更有帮助,甚至更明智的答案。我希望快速轻松地将在 Docker Swarm 上的容器中运行的日志记录到特定于 {{Slot.ID}} 的目录中;这个答案提供了这一点。
    • 效果很好!
    【解决方案3】:

    查看Logback代码,我找到了解决方法:

    rollingPolicy.stop();
    rfappender.stop();
    rollingPolicy.start();
    rfappender.start();
    

    这会导致 Logback 使用新的定义。不过,这仍然是一种解决方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-06
      • 1970-01-01
      • 2011-12-11
      相关资源
      最近更新 更多