LogBack的配置文件详解(一)

本文参考了LogBack官方文档中关于配置的说明

LogBack配置

LogBack配置的加载顺序

logback在启动的时候,会按照下面的顺序加载配置文件:

  1. 在classpath中查找 logback-test.xml 文件。
  2. 在classpath中查找 logback.groovy 文件。
  3. 在classpath中查找 logback.xml 文件。
  4. 如果是 jdk6+,那么会调用ServiceLoader 查找com.qos.logback.classic.spi.Configurator接口的第一个实现类。
  5. 自动使用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
19
package 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<!-- 控制台输出 -->
<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>

<!-- 系统日志级别 -->
<root level="INFO">
<appender-ref ref="console"/>
</root>

</configuration>

其中定义的两个appender的配置表示打印到控制台(appender配置请参考此篇:LogBack的配置详解(二)——appender)。
上面的配置中<root>节点设置的打印级别是“INFO”,指定了名字为“console”的appender。

当执行com.lzumetal.logback.LogBackDemo类的main方法时,root将级别为“INFO”及大于“INFO”的日志信息交给已经配置好的名为“console”的appender处理,“console”appender将信息打印到控制台。
控制台打印日志结果如下

第二种:带有logger的配置,不指定级别,不指定appender。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<!-- 控制台输出 -->
<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>


<logger name="com.lzumetal">
</logger>

<!-- 系统日志级别 -->
<root level="DEBUG">
<appender-ref ref="console"/>
</root>

</configuration>

对上面的配置分析如下:

  1. <logger>的属性name=”com.lzumetal”,将控制com.lzumetal包下的所有类的日志的打印,但是并没用设置打印级别,所以继承他的上级的日志级别“DEBUG”;
  2. <logger>节点没有设置additivity,默认为true,将此logger的打印信息向上级传递;
  3. 该<logger>节点没有设置appender,此logger本身不打印任何信息;
  4. 将root的打印级别设置为“DEBUG”,指定了名字为“console”的appender。

当执行com.lzumetal.logback.LogBackDemo类的main方法时,因为LogbackDemo在包com.lzumetal中,所以首先执行,将级别为“DEBUG”及大于“DEBUG”的日志信息传递给root,本身并不打印;

root接到下级传递的信息,交给已经配置好的名为“console”的appender处理,“console”appender将信息打印到控制台。
打印日志的结果如下

第三种:带有多个logger的配置,指定级别,指定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
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

<!-- 控制台输出 -->
<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">
</logger>

<logger name="com.lzumetal.logback.LogBackDemo" level="INFO" additivity="false">
<appender-ref ref="myAppender"/>
</logger>

<!-- 系统日志级别 -->
<root level="WARN">
<appender-ref ref="console"/>
</root>

</configuration>

对上面的配置分析如下:

  • <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次。

------ 本文完 ------