我在logback.xml中定义了一个logback附加程序,它是一个数据库附加程序,但我很好奇是否有任何方法可以使用定义为bean的我自己的连接池在java中配置附加程序。
我发现类似的事情,但没有实际答案。
我在logback.xml中定义了一个logback附加程序,它是一个数据库附加程序,但我很好奇是否有任何方法可以使用定义为bean的我自己的连接池在java中配置附加程序。
我发现类似的事情,但没有实际答案。
Answers:
这是一个对我有用的简单示例(请注意,在此示例中我使用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;
}
}
Logger
不再公开该addAppender()
方法。
Logger
没有addAppender
方法的人,是因为您要指出Logger
sl4j中的抽象类。如果Logger
从logback
包中指出一种实现,则可以使用addAppender
。这样做的缺点是您的测试代码将与logback
实现耦合。
lc.getLogger(string)
。
作为参考,当您尝试修改负责创建记录器的代码时,为了使记录器正常工作,必须满足一系列规则。
这些规则在slf4j / logback的程序化配置文章中非常有帮助:
现在,我对slf4j / logback的编程配置有了经验。
任务
程序必须为每个处理的输入文件打开单独的日志文件。
任务解决方案
无需通过xml配置登录,而是需要“手动”实例化编码器,附加程序和记录器,然后将它们配置并链接在一起。
警告1
尝试在追加程序之间共享编码器(即PatternLayoutEncoder)时,Logback变得疯狂。
警告1的解决方案
为每个追加程序创建单独的编码器。
警告2
如果编码器和附加器未与日志记录上下文关联,则Logback拒绝记录任何内容。
警告2的解决方案
在每个编码器和附加器上调用setContext,并将LoggerFactory作为参数传递。
警告3
如果未启动编码器和附加程序,则Logback拒绝记录任何内容。
警告3的解决方案
编码器和附加器需要以正确的顺序启动,即首先编码器,然后是附加器。
警告4
当RollingPolicy对象未附加到附加程序时,它们会生成奇怪的错误消息,例如“无法识别日期格式”,例如RollingPolicy对象(即TimeBasedRollingPolicy)。
警告4的解决方案
在RollingPolicy上调用setContext与在编码器和追加器上调用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.setAdditive(false);
log.setLevel(Level.INFO);
log.addAppender(logConsoleAppender);
log.addAppender(logFileAppender);
}
}
java.lang.ClassCastException: org.apache.logging.slf4j.Log4jLoggerFactory cannot be cast to ch.qos.logback.classic.LoggerContext
"Main"
名称似乎无效。Logger.ROOT_LOGGER_NAME
是"ROOT"
。
只是,如果有人要寻找程序化配置的具体示例。
在这里,我设置了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"));
而我的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>
为什么我需要以编程方式配置记录器?因为,我将我的应用程序(Spring Boot)打包到一个jar文件中。因此,Logback.xml文件似乎隐藏在jar中。但是,解包和更改它并不方便。而且我的app.jar旁边不需要任何logback.xml文件。我只有app.yaml文件,其中包含应用程序的所有配置属性。
不允许发表评论(还好吗?),我只想补充三个提示。
关于上述注意事项,如果您有任何问题,只需致电即可
StatusPrinter.print(context);
一切都已经配置后,也就是在已经加入你的追加程序的根/“主”附加器:它会告诉你什么是错的。
我非常喜欢将日志记录级别分隔在不同的文件中。当查找错误时,我首先查找错误文件,依此类推,将它们设置为
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);
}
将根日志记录级别保留在受监视的某些属性文件中,以便每当那里存在一些有效输入时,我只需调用此服务即可实现
@Override
public void setRootLogLevel(Level level) {
if (context != null && context.isStarted()) {
((Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(level);
}
}
与我的新的根记录器级别。