以编程方式配置LogBack appender

时间:2013-06-04 06:13:15

标签: java spring javabeans logback

我在logback.xml中定义了一个logback appender,它是一个DB appender,但我很好奇是否有任何方法可以使用我自己定义为bean的连接池在java中配置appender。

我发现了类似的东西,但从来没有找到真正的答案。

5 个答案:

答案 0 :(得分:103)

这是一个适合我的简单示例(请注意,我在此示例中使用了FileAppender)

import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
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;

public class Loggerutils {

    public static void main(String[] args) {
          Logger foo = createLoggerFor("foo", "foo.log");
          Logger bar = createLoggerFor("bar", "bar.log");
          foo.info("test");
          bar.info("bar");
    }

    private static Logger createLoggerFor(String string, String file) {
          LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
          PatternLayoutEncoder ple = new PatternLayoutEncoder();

          ple.setPattern("%date %level [%thread] %logger{10} [%file:%line] %msg%n");
          ple.setContext(lc);
          ple.start();
          FileAppender<ILoggingEvent> fileAppender = new FileAppender<ILoggingEvent>();
          fileAppender.setFile(file);
          fileAppender.setEncoder(ple);
          fileAppender.setContext(lc);
          fileAppender.start();

          Logger logger = (Logger) LoggerFactory.getLogger(string);
          logger.addAppender(fileAppender);
          logger.setLevel(Level.DEBUG);
          logger.setAdditive(false); /* set to true if root should log too */

          return logger;
    }

}

答案 1 :(得分:14)

您可以通过编程方式配置appender。几乎所有的appender都使用程序化配置进行测试。因此,在logback项目源代码中有许多程序化appender配置的例子。对于logback-core appender,请查看logback-core/src/test/java下的内容,并查看logback-classic/src/test/java下的logback-classic appender。

答案 2 :(得分:7)

作为参考,当您尝试修改负责创建记录器的代码时,必须满足一系列规则才能使记录器工作。

这篇规则在一篇很有帮助的文章Programmatic configuration of slf4j/logback中进行了描述:

  

现在我有slf4j / logback的编程配置经验。

     

<强>任务

     

程序必须为每个已处理的输入文件打开单独的日志文件。

     

任务解决方案

     

不需要通过xml配置logback,而是需要“手动”实例化编码器,追加器和记录器,然后配置它们并将它们链接在一起。

     

警告1

     

尝试在appender之间共享编码器(即PatternLayoutEncoder)时,Logback发疯了。

     

警告解决方案1 ​​

     

为每个appender创建单独的编码器。

     

警告2

     

如果编码器和追加器与记录上下文无关,则Logback拒绝记录任何内容。

     

警告2的解决方案

     

在每个编码器和appender上调用setContext,传递LoggerFactory   作为参数。

     

警告3

     

如果未启动编码器和追加器,则Logback拒绝记录任何内容。

     

警告3的解决方案

     

编码器和appender需要以正确的顺序启动,即第一个编码器,然后是appender。

     

警告4

     

RollingPolicy对象(即TimeBasedRollingPolicy)在未附加到与appender相同的上下文时会产生奇怪的错误消息,例如“日期格式无法识别”。

     

警告解决方案4

     

在RollingPolicy上调用setContext,与编码器和追加器一样。

     

以下是“手动”回溯配置的工作示例:

package testpackage

import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import ch.qos.logback.classic.LoggerContext
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.core.rolling.RollingFileAppender
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy

import org.slf4j.LoggerFactory

class TestLogConfig {

  public static void main(String[] args) {
    LoggerContext logCtx = LoggerFactory.getILoggerFactory();

    PatternLayoutEncoder logEncoder = new PatternLayoutEncoder();
    logEncoder.setContext(logCtx);
    logEncoder.setPattern("%-12date{YYYY-MM-dd HH:mm:ss.SSS} %-5level - %msg%n");
    logEncoder.start();

    ConsoleAppender logConsoleAppender = new ConsoleAppender();
    logConsoleAppender.setContext(logCtx);
    logConsoleAppender.setName("console");
    logConsoleAppender.setEncoder(logEncoder);
    logConsoleAppender.start();

    logEncoder = new PatternLayoutEncoder();
    logEncoder.setContext(logCtx);
    logEncoder.setPattern("%-12date{YYYY-MM-dd HH:mm:ss.SSS} %-5level - %msg%n");
    logEncoder.start();

    RollingFileAppender logFileAppender = new RollingFileAppender();
    logFileAppender.setContext(logCtx);
    logFileAppender.setName("logFile");
    logFileAppender.setEncoder(logEncoder);
    logFileAppender.setAppend(true);
    logFileAppender.setFile("logs/logfile.log");

    TimeBasedRollingPolicy logFilePolicy = new TimeBasedRollingPolicy();
    logFilePolicy.setContext(logCtx);
    logFilePolicy.setParent(logFileAppender);
    logFilePolicy.setFileNamePattern("logs/logfile-%d{yyyy-MM-dd_HH}.log");
    logFilePolicy.setMaxHistory(7);
    logFilePolicy.start();

    logFileAppender.setRollingPolicy(logFilePolicy);
    logFileAppender.start();

    Logger log = logCtx.getLogger("Main");
    log.additive = false;
    log.level = Level.INFO;
    log.addAppender(logConsoleAppender);
    log.addAppender(logFileAppender);
  }
}

答案 3 :(得分:5)

Just, if somebody would looking for a concrete example of programmatic configuration.

Here I setup the charset of ConsoleAppender:

LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
ConsoleAppender<ILoggingEvent> appender =
    (ConsoleAppender) lc.getLogger("appconsole").getAppender("STDOUT");
LayoutWrappingEncoder<ILoggingEvent> enc = 
    (LayoutWrappingEncoder<ILoggingEvent>) appender.getEncoder();
enc.setCharset(Charset.forName("utf-8"));

And my logback.xml:

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
        <charset>866</charset>
        <pattern>[%level] %msg%n</pattern>
    </encoder>
</appender>

<logger name="appconsole">
    <appender-ref ref="STDOUT" />
</logger>

Why I need programmaticaly configure a logger? Because, I packaging my app (Spring Boot) into a jar file. Consequently Logback.xml file is appear to be hide inside a jar. Though, it is not to be convenient to unpackage and change it. And I do not need any logback.xml file beside my app.jar. I have only app.yaml file which contains all configuration properties for app.

答案 4 :(得分:0)

不允许发表评论(还有?),我只想添加三个提示;

  • 关于上述警告,如果您遇到问题,只需添加对

    的调用即可
    StatusPrinter.print(context);
    

    完成所有配置后,即添加完毕后 根目录/&#34;主要&#34; appender:它告诉你出了什么问题。

  • 我非常喜欢将不同文件中的日志记录级别分开;在寻找错误时,我首先查看错误文件,依此类推,将它们设置为

tot_[app name].log   : Level.INFO
deb_[app name].log   : Level.DEBUG
err_[app name].log   : Level.ERROR

通过简单的私有过滤器类(例如

)进行路由
    private static class ThresholdLoggerFilter extends Filter<ILoggingEvent> {

        private final Level level;

        private ThresholdLoggerFilter(Level level){
            this.level = level;
        }

        @Override
        public FilterReply decide(ILoggingEvent event) {
            if (event.getLevel().isGreaterOrEqual(level)) {
                return FilterReply.NEUTRAL;
            } else {
                return FilterReply.DENY;
            }
        }
    }

然后只需致电myFilter.start()myAppender.addFilter(myFilter);

  • 最后,把它放在一起,我通常希望能够动态更改日志级别,因为设置实现了一些简单的界面,如

    public interface LoggingService {
        void setRootLogLevel(Level level);
    }
    

将root日志记录级别保存在一些受监视的属性文件中,以便每当有一些有效输入时,我只是将此服务称为

    @Override
    public void setRootLogLevel(Level level) {
        if (context != null && context.isStarted()) {
        ((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(level);
        }
    }

使用我的新根记录器级别。