一文理解logback
Posted 小白懂编程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文理解logback相关的知识,希望对你有一定的参考价值。
Logback是由log4j创始人设计的又一个开源日志组件,可以认为是log4j的改进版本。非常简单灵活,是目前主流的日志记录工具。推荐你也开始使用logback。
很多人都会使用log4j或logback。但我也相信,大多数人其实并不是很好的理解了它们,大部分场景下都是复制个配置文件改下就应付了。其实稍微花点时间研究下,就能更加合理的配置和使用logback。
开始使用
maven或gradel引入logback的两个jar包即可开始使用了。
gradle:
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
compile group: 'ch.qos.logback', name: 'logback-core', version: '1.1.8'
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.8'
}
新建个类即可开始使用
package bumishi.logback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by @bumishi(http://bumishi.cn) on 2017/1/19.
*/
public class LogbackStudy {
public static void main(String[] arg){
//创建一个名字为test的logger
Logger logger= LoggerFactory.getLogger("test");
logger.debug("debug");
logger.info("info");
logger.warn("warn");
logger.error("error");
}
}
logback需要一个配置文件来描述以怎样的格式输出日志,以及日志要输出到哪里去,以及日志的级别等。
加载配置文件
程序启动时,logback先从classpath中查找一个名为logback.groovy的配置文件
如果没有找到,再查找名为logback-test.xml的文件
如果没有找到,再查找名为logback.xml的文件
如果没有找到,会尝试从classpath的 META-INF\services\ch.qos.logback.classic.spi.Configurator文件中解析一个实现了 com.qos.logback.classic.spi.Configurator接口的完整类作为一个配置对象来配置
如果还是没有找到可以配置的方式,那么logback默认地会调用BasicConfigurator,创建一个最小化配置。最小化配置由一个关联到根logger的ConsoleAppender 组成。输出用模式为
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
的PatternLayoutEncoder 进行格式化。根logger 默认级别是 DEBUG。
此外,我们也可以在启动程序时通过命令行参数指定。
通过指定一个名为 “logback.configurationFile”的Java system属性,这个属性的值可以是一个url,一个classpath中的文件,或者一个外部的文件。
java -Dlogback.configurationFile=/path/to/config.xml chapters.configuration.MyApp1
需要注意的是,这个文件的扩展名必须是.xml或.groovy,其它扩展名将会被忽略。
通常,我们在测试环境下使用logback-test.xml,生产环境使用logback.xml
这里,我们创建一个logback-test.xml
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{MM/dd/yyyy HH:mm:ss} %-5level [%thread%X{sourceThread}]%logger{24} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/admin-manage/log.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/var/log/admin-manage/log.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{MM/dd/yyyy HH:mm:ss} %-5level ${version} [%thread]%logger{16} - %msg%n
</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
我们来逐一解释配置中的项目。
configuration是根节点。appender是用来表示日志要输出到哪里的组件。encoder用来将日志信息解析成具有一定格式的信息。
我们创建了一个名为STDOUT,类型为ch.qos.logback.core.ConsoleAppender的appender,这个appender用于把日志信息输出到控制台,就像System.out.println()一样。其中的pattern表示一个格式,%d表示日期,%d{MM/dd/yyyy HH:mm:ss} 表示以MM/dd/yyyy HH:mm:ss 这个格式显示当前时间,%thread表示线程名,%-5:级别从左显示5个字符宽度,level是日志级别,%msg:日志消息,%n是换行符。我们根据输出来的日志信息就能明白其中的含义。
我们同时创建了一个名为FILE,类型为ch.qos.logback.core.rolling.RollingFileAppender的appender,这是一个可以将日志输出到一个文件的appender,并且可以按照日期自动滚动,不至于让所有日志都写在一个文件上。rollingPolicy是一种文件滚动策略,可以让日志文件按日或按月归档。
上面的配置表示按照每天生成日志文件,最多保留7天,日志文件存放在/var/log/admin-manage/log.log。每过一天,日志名就变成类似log.2017-01-19.log.gz的形式。
只配置appender并不能直接输出日志,logback中,appender是要给logger用的,我们需要配置logger。
每个logger都是ch.qos.logback.classic.Logger的一个实例,每个logger有一个名称,有一个级别,以及0个或多个appender,这意味着同一条日志信息可以同时输出到多个地方去。
整个logback中,最为重要的部分就是理解logger的继承层次了,绝大多数人并不理解。理解了这个后你就能随心所欲的使用logback来按你你想要的方式来输出日志了。
logback及log4j中logger的继承层次都类似。
logger是一个具备父子关系的树结构。最顶端的logger是一个固定名称为ROOT的logger,所有的logger都是它的孩子,就像Java的Object一样。然而logger的继承层次却是完全根据logger的name来决定的。logback根据logger的name按照”.”来进行分割,就像Java的包名一样。名为com.bumishi的logger是名为com的logger的子logger,名为com的logger是ROOT的子logger,任何一个logger如果向上找不到父logger那它的父logger就是ROOT。
在logback的配置文件中,ROOT logger用<root>表示,其它logger用<logger>表示。每个logger都有几个属性:
name:名称,根据此名称建立继承层次结构
level:级别,如debug,info,warn,error等,级别依次越来越高,给logger指定高级别时,低于这个级别的日志信息将不会被发送到appender。
additivity:表示此logger输出的日志是否要向上传递到父logger的appender,默认是true。传递到父logger的意思是,日志信息除了在当前logger的appender中输出,还会在父logger中的appender输出。
appender列表
一个logger可以有0个或多个appdner,通过appender-ref节点引用前面定义的appender。
上面的配置中,我们只配置了一个根logger——root,指定了它的级别为debug,指定了appender输出到控制台。
由于配置的是root,所有这个配置会对所有的logger有效,我们在应用中任何名称的logger输出的所有级别大于或等于debug的信息都将输出到控制台中。
我们运行上述程序即可看到效果:
01/19/2017 21:58:12 DEBUG [main]test - debug
01/19/2017 21:58:12 INFO [main]test - info
01/19/2017 21:58:12 WARN [main]test - warn
01/19/2017 21:58:12 ERROR [main]test - error
我们尝试定义多个不同的logger
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{MM/dd/yyyy HH:mm:ss} %-5level [%thread%X{sourceThread}]%logger{24} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/admin-manage/log.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/var/log/admin-manage/log.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{MM/dd/yyyy HH:mm:ss} %-5level ${version} [%thread]%logger{16} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="test1" level="info"/>
<logger name="test2" level="info" additivity="false"/>
<logger name="test3" level="warn" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="test4" level="warn" >
<appender-ref ref="STDOUT"/>
</logger>
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
在Java中分别运行下不同logger的输出结果
package bumishi.logback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by @bumishi(http://bumishi.cn) on 2017/1/19.
*/
public class LogbackStudy {
public static void main(String[] arg) {
print("test1");
print("test2");
print("test3");
print("test4");
}
public static void print(String name) {
Logger logger = LoggerFactory.getLogger(name);
logger.debug("debug");
logger.info("info");
logger.warn("warn");
logger.error("error");
}
}
结果:
1/19/2017 22:58:24 INFO [main]test1 - info
01/19/2017 22:58:24 WARN [main]test1 - warn
01/19/2017 22:58:24 ERROR [main]test1 - error
01/19/2017 22:58:24 WARN [main]test3 - warn
01/19/2017 22:58:24 ERROR [main]test3 - error
01/19/2017 22:58:24 WARN [main]test4 - warn
01/19/2017 22:58:24 WARN [main]test4 - warn
01/19/2017 22:58:24 ERROR [main]test4 - error
01/19/2017 22:58:24 ERROR [main]test4 - error
你是否能理解这个结果呢?
我一个一个解释下:
如果我们在加两个这样的logger
<logger name="com.test4" level="warn" >
<appender-ref ref="STDOUT"/>
</logger>
<logger name="com" level="warn" >
<appender-ref ref="STDOUT"/>
</logger>
用com.test4打印,那么就会出现3次了。
print("com.test4");
01/19/2017 23:10:36 WARN [main]com.test4 - warn
01/19/2017 23:10:36 WARN [main]com.test4 - warn
01/19/2017 23:10:36 WARN [main]com.test4 - warn
01/19/2017 23:10:36 ERROR [main]com.test4 - error
01/19/2017 23:10:36 ERROR [main]com.test4 - error
01/19/2017 23:10:36 ERROR [main]com.test4 - error
专注技术研究
以上是关于一文理解logback的主要内容,如果未能解决你的问题,请参考以下文章
一文详细了解logback之日志打印FileAppender
一文讲尽门面日志slf4j和log4jlog4j2logback依赖jar引用关系