本文参考了LogBack官方文档中关于配置的说明。
LogBack配置
LogBack配置的加载顺序
logback在启动的时候,会按照下面的顺序加载配置文件:
- 在classpath中查找 logback-test.xml 文件。
- 在classpath中查找 logback.groovy 文件。
- 在classpath中查找 logback.xml 文件。
- 如果是 jdk6+,那么会调用ServiceLoader 查找com.qos.logback.classic.spi.Configurator接口的第一个实现类。
- 自动使用ch.qos.logback.classic.BasicConfigurator,在控制台输出日志 。
PS:如果是Maven项目,并且在src/test/resources
目录下创建一个logback-test.xml
文件,maven打包时则可以设置不将src/test/resources
下的文件打包,这样就可以在测试环境使用logback-test.xml
文件,而生产环境则使用src/main/resources
目录下创建一个logback.xml
文件。
根节点<configuration>
根节点<configuration>的属性
- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认每分钟扫描一次配置文件。
- scanPeriod:当scan为true时,scanPeriod用来设置每隔多久扫描一次配置文件,检查配置是否有修改。可选时间单位为:milliseconds, seconds, minutes or hours,默认是milliseconds。
- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
例如:1
2
3<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 其他配置省略-->
</configuration>
根节点<configuration>的子节点
根节点<configuration>下最主要的子节点包括三个:appender、logger和root。其它可能也会用到property等节点。
<property>节点:设置变量
用来定义变量值的标签,<property> 有两个属性,name和value;其中name的值是变量的名称,value的值时变量定义的值。通过<property>定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。
例如使用<property>定义日志存储的目录和日志打印的格式,然后在配置中就可以使用。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<configuration>
<property name="LOG_HOME" value="/opt/logs"/>
<property name="LOG_FORMAT" value="[%-5level] %d{yyyy-MM-dd HH:mm:SSS} [%thread] %logger{25} : %msg%n"/>
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_HOME}/info.log.%d{yyyy-MM-dd}</FileNamePattern>
<MaxHistory>90</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_FORMAT}</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>
</configuration>
<root>和<logger>节点
<logger>节点
<logger>节点用来设置某一个包、或者某一个类或者是某个名字的日志配置。<logger>标签包含一个name属性,一个可选的level和一个可选的additivity属性。
- name:用来指定受此logger约束的某一个包、具体的某一个类或者是日志名字。
- level:用来设置打印级别,等于或高于这个级别的日志将会被这个logger处理。设置的值与大小写无关,包括:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前logger将会继承上级的level级别。
- additivity:是否向上级logger传递打印信息。默认是true。
<logger>可以包含零个或多个<appender-ref>元素,标识这个appender将会被添加到这个logger。
<root>节点
也是<logger>元素,但是它是根loger。只有一个level属性,应为已经被命名为”root”。
- level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能设置为INHERITED或者同义词NULL。默认是DEBUG级别。
<root>可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个logger。
<logger>和<root>使用示例
测试的java类:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package com.lzumetal.logback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogBackDemo {
private static final Logger log = LoggerFactory.getLogger(LogBackDemo.class);
public static void main(String[] args) {
log.trace("======trace");
log.debug("======debug");
log.info("======info");
log.warn("======warn");
log.error("======error");
}
}
配置文件是logback-test.xml,分以下几种情况讨论。
第一种:只配置root
1 | <?xml version="1.0" encoding="UTF-8"?> |
其中定义的两个appender的配置表示打印到控制台(appender配置请参考此篇:LogBack的配置详解(二)——appender)。
上面的配置中<root>节点设置的打印级别是“INFO”,指定了名字为“console”的appender。
当执行com.lzumetal.logback.LogBackDemo
类的main方法时,root将级别为“INFO”及大于“INFO”的日志信息交给已经配置好的名为“console”的appender处理,“console”appender将信息打印到控制台。
控制台打印日志结果如下
第二种:带有logger的配置,不指定级别,不指定appender。
1 | <?xml version="1.0" encoding="UTF-8"?> |
对上面的配置分析如下:
- <logger>的属性name=”com.lzumetal”,将控制
com.lzumetal
包下的所有类的日志的打印,但是并没用设置打印级别,所以继承他的上级的日志级别“DEBUG”; - <logger>节点没有设置additivity,默认为true,将此logger的打印信息向上级传递;
- 该<logger>节点没有设置appender,此logger本身不打印任何信息;
将root的打印级别设置为“DEBUG”,指定了名字为“console”的appender。
当执行com.lzumetal.logback.LogBackDemo
类的main方法时,因为LogbackDemo在包com.lzumetal
中,所以首先执行
root接到下级传递的信息,交给已经配置好的名为“console”的appender处理,“console”appender将信息打印到控制台。
打印日志的结果如下
第三种:带有多个logger的配置,指定级别,指定appender
1 | <?xml version="1.0" encoding="UTF-8"?> |
对上面的配置分析如下:
<logger name="com.lzumetal.logback.LogBackDemo" level="INFO" additivity="false"\>
控制com.lzumetal.logback.LogBackDemo
类的日志打印,打印级别为“INFO”;additivity属性为false,表示此loger的打印信息不再向上级传递;指定了名字为“myAppender”的appender。<logger name="com.lzumetal"\>
将控制com.lzumetal
包下的所有类的日志的打印,但是并没用设置打印级别,所以继承他的上级的日志级别“WARN”;没有设置additivity,默认为true,将此logger的打印信息向上级传递;没有设置appender,此logger本身不打印任何信息。 - <root level=”WARN”>将root的打印级别设置为“WARN”,指定了名字为“console”的appender。
当执行com.lzumetal.logback.LogBackDemo
类的main方法时,先执行<logger name="com.lzumetal.logback.LogBackDemo" level="INFO" additivity="false"\>
,将级别为“INFO”及大于“INFO”的日志信息交给此loger指定的名为“myAppender”的appender处理,在控制台中打出日志,不再向次logger的上级 <logger name="logback"\>
传递打印信息。
<logger name="com.lzumetal"\>
未接到任何打印信息,当然也不会给它的上级root传递任何打印信息;
日志打印效果如图
如果将<logger name="com.lzumetal.logback.LogBackDemo" level="INFO" additivity="false"\>
修改为<logger name="logback.LogbackDemo" level="INFO" additivity="true"\>
,那么这个logger的日志向它的上级logger<logger name="com.lzumetal"\>
传递,而<logger name="com.lzumetal" \>
本身不打印,但会向他的上级logger<root level="WARN"\>
传递,<root level="WARN"\>
会通过“console”appender输出日志。
最终的结果是,logger本身打印一次,root打印了一次,如下图:
如果<logger name="com.lzumetal"\>
也指定一个日志的appender,那么结果会怎么样呢?比如1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_FORMAT" value="[%-5level] %d{yyyy-MM-dd HH:mm:SSS} [%thread] %logger{25} : %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>控制台appender|[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %class.%method : %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 业务日志输出 -->
<appender name="myAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>自定义Appender|[%-5level] %d{yyyy-MM-dd HH:mm:SSS} [%thread] %logger{25} : %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<logger name="com.lzumetal" level = "INFO">
<appender-ref ref="myAppender"/>
</logger>
<logger name="com.lzumetal.logback.LogBackDemo" level="INFO" additivity="true">
<appender-ref ref="myAppender"/>
</logger>
<!-- 系统日志级别 -->
<root level="WARN">
<appender-ref ref="console"/>
</root>
</configuration>
依照上面的分析,日志应该要被打印三次,“console”appender打印一次,“myAppender”打印两次,事实上确实如此,日志打印的效果如图:
logger中level属性的传递性
- 前面说到的,如果logger中未设置level属性,那么当前logger将会继承上级的level级别
- 如果logger设定了level级别,并且日志向上级logger传递,则传递到父级logger中时,父级logger的level属性将会被覆盖。
比如上面的配置文件改成如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_FORMAT" value="[%-5level] %d{yyyy-MM-dd HH:mm:SSS} [%thread] %logger{25} : %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>控制台appender|[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %class.%method : %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
</appender>
<!-- 业务日志输出 -->
<appender name="myAppender" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>自定义Appender|[%-5level] %d{yyyy-MM-dd HH:mm:SSS} [%thread] %logger{25} : %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<logger name="com.lzumetal" level="ERROR">
<appender-ref ref="myAppender"/>
</logger>
<logger name="com.lzumetal.logback.LogBackDemo" level="INFO" additivity="true">
<appender-ref ref="myAppender"/>
</logger>
<!-- 系统日志级别 -->
<root level="WARN">
<appender-ref ref="console"/>
</root>
</configuration>
打印日志效果为:
可以看到自定义Appender中的info级别日志也打印了2次,而不是只有error级别的日志打印2次。