之前博文有专门介绍过基于Log4j Appender 实现大数据平台组件日志的采集, 本篇主要对java项目中经常会接触到的logback.xml文件的配置做一个介绍和总结.
下面是一个logback配置demo, 常用的配置都有, 一一介绍下每个配置的作用.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_HOME" value="d:/opt/module/logs" />
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<appender name="rollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/app.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<!-- 将某一个包下日志单独打印日志 -->
<logger name="com.bigdata.logger.LoggerExample"
level="INFO" additivity="false">
<appender-ref ref="rollingFile" />
<appender-ref ref="console" />
</logger>
<root level="error" additivity="false">
<appender-ref ref="console" />
</root>
</configuration>
配置说明:
项目结构:
maven 配置:
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.6</version>
</dependency>
</dependencies>
测试代码:
public class LoggerExample {
private static final Logger logger = LoggerFactory.getLogger(LoggerExample.class);
public static void main(String[] args) {
logger.info("Example log from {}", LoggerExample.class.getSimpleName());
logger.error("Error log");
}
}
直接运行的结果:
console和app.log文件的结果一样
修改 additivity="true
<logger name="com.bigdata.logger.LoggerExample" level="INFO" additivity="true">
再次运行结果:
可以看出app.log正常, 但是cosole 上打印了重复的日志, 说明命中了console appender两次, log和root 各一次, 但是奇怪的是, 第一条info日志为什么会重复, 因为root level="ERROR", 理论上info 日志级别比ERROR级别要低, 不应该在console里出现才对.
我们看下logback相关的源码是如何处理的.
/**
* Invoke all the appenders of this logger.
*
* @param event The event to log
*/
public void callAppenders(ILoggingEvent event) {
int writes = 0;
for (Logger l = this; l != null; l = l.parent) {
writes += l.appendLoopOnAppenders(event);
if (!l.additive) {
break;
}
}
// No appenders in hierarchy
if (writes == 0) {
loggerContext.noAppenderDefinedWarning(this);
}
}
从代码我们可以看出, logback 的整个输出是从logger子节点开始往上遍历, 如果additive = false, 就直接break 循环直接结束, 如果break = true, 会继续往上寻找父节点,直到最终 l == null. 同时会记录writes, writes == 0,认为没有定义appender输出源
代码没有关于日志级别的控制. 所以以后如果只希望打印日志到子节点的appeder, 父节点的appender忽略, 就设置additivity = false, 默认值为true, 这样日志就不会重复了.
主要对logback.xml 常用配置的作用介绍, 通过logback 的相关源码对additivity参数有了更深的认识. additivity 默认值为true, 如果不希望在某些场景下打印重复的日志, 可以设置为false, additivity 配置不受level配置的影响.