一、概述
记得前些年项目中的日志记录,最开始用的是log4j。对一般的项目使用还算可以,肯定谈不上很好,但还是可以勉强用的。后来有了log4j 2、commons logging、slf4j、logback等日志框架。但slf4j不是具体的日志实现框架,而是提供了常用的日志接口,在使用的时候我们可以直接调用其接口,通过使用提供的,隐藏了日志的具体实现。logback则提供了日志记录的功能。
二、logback介绍
logback的性能比log4j更好,在某此操作上,其性能得到了显著的提升。log4j和logback源自同一个作者,但logback是log4j的升级,所以logback自然比log4j有很多优秀的地方。不过logback和log4j是比较相似的,如果你对log4j很熟悉或者使用过log4j,那对logback就能很快的应用起来。下面列出一部分logback的优点:
2.1,logback原生实现了slf4j的api
logback-classic实现了slf4j,但我们感觉不到logback-classic。如果我们要改用log4j会很容易,换相应的jar就好,不需要去更改slf4j的api实现。
2.2,支持xml、Groovy方式进行配置
2.3,支持配置文件中加入条件判断
通过在配置文件中加入条件判断,会增加灵活度,以处理不同的情况。比如通过<if>、<then>和<else>来配置日志适用于不同的环境中,一个配置文件可以用到开发、测试、生产、演示环境中。当然也可以一个环境写一个配置文件。
2.4,更为强大的过滤器
比如在诊断某一问题时,需要打出日志。对log4j只有降低日志级别,但这样打打印出很多不需要的日志,同时也影响性能。对logback,可以继续保持日志级别,然后除掉某种特殊的情况。在使用中,可以针对不同用户的登陆打印不同级别的日志,而且配置也不复杂,可参考MDCFilter。
2.5,更充分的测试
到目前为此,logback发展已经有些年了,经受住了广大用户的测试。
2.6,丰富的免费文档
官网上有很多文档,另外也有许多同行写的一些使用说明文档可供参考。
2.7,自动重载有变更的配置文件
当配置文件有了修改,logback-classic可以自动重新加载配置文件。扫描的过程快而且安全,它并不需要重新创建一个扫描线程。可通过<configuration>标签的scan和scanPeriod来配置。
2.8,自动压缩历史日志
RollingFileAppender在产生新日志文件时,自动压缩日志。同时压缩是个异步的过程,在压缩的过程中,并不会影响应该的使用。
2.9,打印异常信息时自动包含package名称及版本号
2.10,快速实现
logback的内核进行了重写,在一些地方性能有明显的提升,且初始化内存的加载也更小了。
2.11,自动去除旧的日志文件
可以控制历史日志文件的保留时间,如果过期了会被清除。此功能涉及<maxHistory>标签。
2.12,SiftingAppender
SiftingAppender可以根据给定的一个运行参数来分割日志文件。比如可以区别日志事件,跟进用户的session,可根据要求一个用户产生一个日志文件。
2.13,Lilith
Lilith是log事件的观察者,是logback的logging和AccessEvent查看工具,目录已经更新到8.1以上了。和log4j的chainsaw类似。面Lilith还可处理大数量的log数据。
2.14,谨慎的模式和非常友好的恢复
在谨慎模式下,多个FileAppender实例跑在多个JVM下,能够安全的写进同一个日志文件中。RollingFileAppender会有些限制。logback的FileAppender和它的子类包括RollingFileAppender能够非常友好的从I/O异常中恢复。
三、logback配置介绍
3.1,logback配置文件结构
根节点为<configuration>标签,其子节点有Appender、Logger、Root。如下图所示。
3.2,标签与属性解释说明
下面对logback配置的部分标签及标签属性进行解释说明。
标签或属性名 | 解释说明 |
<configuration> | 配置的根节点 |
--scan | 为ture时,若配置文件属性改变会被扫描并重新加载,默认为true |
--scanPeriod | 监测配置文件是否有修改的时间间隔,若没给出时间单位,默认单位为毫秒;默认时间为1分钟;当scan="true"时生效 |
--debug | 为true时,将打出logback的内部日志信息,实时查看logback运行状态;默认值为false |
<contextName> | 上下文名称,默认为“default”,使用此标签可设置为其它名称,用于区分不同应用程序的记录;一旦设置不能修改 |
<appender> | <configuration>的子节点,负责写日志的组件,有name和class两个必要属性 |
-name | addender的名称 |
-class | appender的全限定名,就是对应的某个具体的Appender类名,比如ConsoleAppender、FileAppender |
-append | 为true地,日志被追加到文件结尾,如果是flase,清空现存的文件,默认值为true |
3.3,默认规则
日志级别为:TRACE < DEBUG < INFO < WARN < ERROR。
如果logback-test.xml和logback.xml都不存在,logback默认地调用BasicConfigurator,然后创建一个最小化的配置。此配置由一个关联到根logger的ConsoleAppender组成,输出结果使用模式为%d{HH:mm:ss.SSS} [%thread] % -5level %logger{36} -%msg %n的PatternLayoutEncoder进行格式化。默认的级别为DEBUG。
3.4,格式化参数说明
在日志的pattern中,%d表示日期,%thread表示线程名,%-5level表示日志级别从左显示5个字符内容,%msg表示日志消息内容,%n表示换行。它们一起配合使用对日志的输出内容进行格式化。下面举例说明。
%d{yyyy-MM-dd HH:mm:ss.SSS},表示对时间进行按照yyyy-MM-dd HH:mm:ss.SSS格式进行格式化输出,例如2017-07-07 12:07:07.222;
Conversion Pattern | Result |
---|---|
%d | 2006-10-20 14:06:49,812 |
%date | 2006-10-20 14:06:49,812 |
%date{ISO8601} | 2006-10-20 14:06:49,812 |
%thread和%-5level觉得没什么可以说的;
%logger{36}表示logger名称最长为36个字符,如果不够36就是有多少就显示多少;
Conversion specifier | Logger name | Result |
---|---|---|
%logger | mainPackage.sub.sample.Bar | mainPackage.sub.sample.Bar |
%logger{0} | mainPackage.sub.sample.Bar | Bar |
%logger{5} | mainPackage.sub.sample.Bar | m.s.s.Bar |
%logger{10} | mainPackage.sub.sample.Bar | m.s.s.Bar |
%logger{15} | mainPackage.sub.sample.Bar | m.s.sample.Bar |
%logger{16} | mainPackage.sub.sample.Bar | m.sub.sample.Bar |
%logger{26} | mainPackage.sub.sample.Bar | mainPackage.sub.sample.Bar |
%msg显示的日志的内容,%n换行,主要是用于方便查看日志,如果所有的日志都在一行,那真的看不下去了。
四、logback使用说明
4.1,具体使用说明
以下日志配置是当前在做一个项目时配置的内容。
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true" scan="true" scanPeriod="60">
<!-- 设置日志的存储路径,方便后面引用 -->
<property name="log.dir" value="E:/data/logs/capabilityService" />
<property name="max.history" value="30" />
<!-- 活动文件的最大大小 -->
<property name="max.file.size" value="100MB" />
<!-- 所有归档日志文件的总大小/容量 -->
<property name="total.size.cap" value="10G" />
<!-- 控制台日志的Appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--<Encoding>UTF-8</Encoding>-->
<!--<layout class="ch.qos.logback.classic.PatternLayout">-->
<!--<!– 格式化输出 –>-->
<!--<pattern>[%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} -%msg%n</pattern>-->
<!--</layout>-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] - %logger{50} -- %msg%n</pattern>
</encoder>
</appender>
<!-- 错误日志 输出日志文件-->
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 根据文件名称的模式,设置按天回滚 -->
<fileNamePattern>${log.dir}/com.worldStar-error-%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 最大历史天数,即保存多少天的日志文件 -->
<maxHistory>${max.history}</maxHistory>
</rollingPolicy>
<!-- 对记录事件进行格式化 -->
<encoder charset="UTF-8" class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%-5level] - %d{HH:mm:ss.SSS} [%thread] %logger{50} -- %msg%n</pattern>
</encoder>
</appender>
<!-- 访问日志的Appender -->
<appender name="ACCESS" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/com.worldStar-access-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${max.history}</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8" class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%-5level] - %d{HH:mm:ss.SSS} [%thread] %logger{36} -- %msg%n</pattern>
</encoder>
</appender>
<!-- 监控日志的Appender -->
<appender name="MONITOR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/com.worldStar-monitor-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${max.history}</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8" class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%-5level] - %d{HH:mm:ss.SSS} [%thread] %logger{36} -- %msg%n</pattern>
</encoder>
</appender>
<!-- 缓存日志的Appender -->
<appender name="CACHE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 -->
<fileNamePattern>${log.dir}/com.worldStar-cache-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${max.history}</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8" class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%-5level] - %d{HH:mm:ss.SSS} [%thread] [%logger{36}] -- %msg%n</pattern>
</encoder>
</appender>
<!-- 操作日志的Appender -->
<appender name="OPERATOR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.dir}/com.worldStar-operator-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>${max.history}</maxHistory>
</rollingPolicy>
<encoder charset="UTF-8" class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>[%-5level] - %d{HH:mm:ss.SSS} [%thread] [%logger{36} -- %msg%n]</pattern>
</encoder>
</appender>
<!-- springframework的日志 -->
<logger name="org.springframework" level="ERROR" />
<!-- apache的日志 -->
<logger name="org.apache" level="ERROR" />
<!-- 这里addivitity要为false,否则STDOUT的日志也会达到ERROR里 -->
<!-- 监控日志 -->
<logger name="WORLDSTAR_MONITOR" additivity="false" level="INFO">
<appender-ref ref="MONITOR" />
</logger>
<!-- 错误日志 -->
<logger name="WORLDSTAR_ERROR" additivity="false" level="DEBUG">
<appender-ref ref="ERROR" />
</logger>
<!-- 访问日志 -->
<logger name="WORLDSTAR_ACCESS" addivitity="false" level="INFO">
<appender-ref ref="ACCESS" />
</logger>
<!-- 缓存日志 -->
<logger name="WORLDSTAR_CACHE" additivity="false" level="INFO">
<appender-ref ref="CACHE" />
</logger>
<!-- 操作日志 -->
<logger name="WORLDSTAR_OPERATOR" additivity="false" level="INFO">
<appender-ref ref="OPERATOR" />
</logger>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
addivitity用于children-logger是否使用root-logger配置的appender进行输出。为false时表示只用当前logger的appender,为true时表示当前logger的appender-ref和root-logger的appender-ref都有效。
如果打印多个参数,示例如下:
logger.info( "=========TradeCenterController.applyOrder:ftrademapping={},price={},count={},buyType={},firstOrderId={}",
ftrademapping, price, count, buyType, firstOrderId);
4.2,总结
logback使用过程中,要配置输出日志的添加器Appender、日志打印的子节点logger和根节点root。日志的输出是从子节点开始,如果子节点有输出内容则直接输入到根节点,如果子节点没有输出内容,则判断logger节点的additivity,是否向上级Root传递,如果传递的话则使用Root的输出,否则就不打印日志。
五、第三方工具、扩展
5.1,Lilith
这个在文章的上面提到过,是logback的Logging和AccessEvent查看器。
5.2,Logback-akka
由几个基于akka的logback实用程序组成,包括ActorAppender,HoptoadActorAppender和Logstash redis appender。
5.3,Logback-android
可以将logback强大的功能应用在Android上。
5.4,Simpledb-appender
Logback Appender可以写入Amazon SimpleDB。
5.5,logback-configuration
一个服务层(使用Spring)和一个REST风格的接口,它提供了以下方法:添加或更新日志,解析日志文件,解析logback配置文件,并上载logback配置文件并重新加载它。
5.6,Logback-gelf
可以通过GELF消息将消息记录到Graylog2服务器。
5.7,Logback-testing
TestNG Reporter的logback appender。