我在logback.xml中定义了一个logback appender,它是一个DB appender,但我很好奇是否有任何方法可以使用我自己定义为bean的连接池在java中配置appender。
我发现了类似的东西,但从来没有找到真正的答案。
答案 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);
}
}
使用我的新根记录器级别。