本文参考了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 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>
|
对上面的配置分析如下:
- <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中,所以首先执行,将级别为“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次。