简介
Logback是由log4j的创始人Ceki Gulcu设计的,并通过了严格充分的测试。它比所有现有的日志系统都要快,而且占用空间更小,还提供了在其他日志系统中没有的独特而有用的特性。
logback详解
log level
logback的日志级别,如下图
logback配置
在项目中使用logback时,它会默认在项目的classpath路径下按顺序查找名为logback-test.xml、logback.groovy、logback.xml的配置文件,如果上述文件均未找到,则使用默认配置(默认日志输出级别为debug)。
logback.xml
在用户没有对logback进行任何配置的情况下,logback可以使用默认配置输出简单的日志到控制台。但在实际工作中,我们通常对项目日志的输出有更多的要求,比如将日志文件按天分割、将日志文件按大小进行分割、定期删除旧日志等。因此需要在项目中创建logback的配置文件,当在项目的classpath路径下存在logback.xml(或者logback-test.xml、logback.groovy),logback框架能够自动扫描到它并读取配置。下面是一个简单的logback配置文件示例:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
在MyApp1的mian方法加入下面代码
public static void main(String[] args) {
// 本示例logback实现SLF4J的API
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
// 打印logback的内部运行状态
StatusPrinter.print(lc);
...
}
运行main方法,控制台输出如下:
17:44:58,578 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback-test.xml]
17:44:58,671 |-INFO in ch.qos.logback.classic.joran.action.ConfigurationAction - debug attribute not set
17:44:58,671 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
17:44:58,687 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [STDOUT]
17:44:58,812 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Popping appender named [STDOUT] from the object stack
17:44:58,812 |-INFO in ch.qos.logback.classic.joran.action.LevelAction - root level set to DEBUG
17:44:58,812 |-INFO in ch.qos.logback.core.joran.action.AppenderRefAction - Attaching appender named [STDOUT] to Logger[root]
17:44:58.828 [main] INFO chapters.configuration.MyApp2 - Entering application.
17:44:58.828 [main] DEBUG chapters.configuration.Foo - Did it again!
17:44:58.828 [main] INFO chapters.configuration.MyApp2 - Exiting application.
configuration
<configuration>
是logback配置文件的根节点,有scan、sacnPeriod、debug、packagingData等属性。
- debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。(为true时和上面在MyApp1的main方法加入的两行代码效果相同)
- scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
- scanPeriod: 设置扫描配置文件的时间间隔,默认单位为毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
配置示例如下:
<configuration scan="true" scanPeriod="60 seconds" debug="false" packagingData="false">
...
</configuration>
configuration节点主要又包含appdender、logger、root三个标签,如下图:
Configuring Appenders
什么是Appender?
Logback委派任务将日志事件写入名为appenders的组件。Appenders必须实现ch.qos.logback.core.Appender 。
ch.qos.logback.core.AppenderBase类是实现Appender接口的抽象类。它提供了所有appenders共享的基本功能,例如获取或设置名称的方法、激活状态、布局和过滤器。
OutputStreamAppender是另外三个appender的超类,即ConsoleAppender, FileAppender,RollingFileAppender。
OutputStreamAppender将事件附加到java.io.OutputStream,这个类为其他appenders的构建提供了基本服务,如下图所示。
下面介绍几个常用的Appender
- ConsoleAppender
ConsoleAppender,顾名思义,在控制台上输出。示例:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
- FileAppender
FileAppender,一个OutputStreamAppender的子类,作用是将日志输出到文件。目标文件可以指定,如果该文件已经存在,它将根据附加属性的值被追加或截断。示例:
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>testFile.log</file>
<append>true</append>
<!-- set immediateFlush to false for much higher logging throughput -->
<immediateFlush>true</immediateFlush>
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
Uniquely named files (by timestamp)
在应用程序开发阶段或短期应用程序(例如批处理应用程序)期间,希望在每个新应用程序启动时创建一个新的日志文件。这在元素的帮助下很容易做到。示例:
<configuration>
<!-- Insert the current time formatted as "yyyyMMdd'T'HHmmss" under
the key "bySecond" into the logger context. This value will be
available to all subsequent configuration elements. -->
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!-- use the previously created timestamp to create a uniquely
named log file -->
<file>log-${bySecond}.txt</file>
<encoder>
<pattern>%logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
-
RollingFileAppender
RollingFileAppender将FileAppender的功能进行扩展,提供了切割日志文件的功能。例如,RollingFileAppender可以记录日志到一个名为log.txt的文件,一旦满足一定条件,将其日志目标更改为另一个文件。
在使用时,RollingFileAppender必须同时具有RollingPolicy和TriggeringPolicy设置。但是,如果它的RollingPolicy也实现TriggeringPolicy接口,那么只需要显式地指定前者。 -
TimeBasedRollingPolicy
时间基准滚动策略可能是最流行的滚动策略。它定义了一个基于时间的滚动策略,例如每日或每月。时间的滚动策略承担了翻转的责任,同时也承担了触发的滚动。TimeBasedTriggeringPolicy实现了RollingPolicy和TriggeringPolicy接口。
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logFile.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 30 days' worth of history capped at 3GB total size -->
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
- SizeAndTimeBasedRollingPolicy
有时候可能希望按日期对文件进行存档,但同时限制每人日志文件的大小,这时候可以使用SizeAndTimeBasedRollingPolicy达到目的。
<configuration>
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>mylog.txt</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="ROLLING" />
</root>
</configuration>
Appender详解
<appender>
节点本身有两个强制属性,分别是name和class。name属性指定appender的名称,而class属性指定要实例化的appender类的完全限定名。<appender>
标签内可能包含0或1 个<layout>
标签,0或多个<encoder>、<filter>
标签。下图是<appender>
的内部结构图:
appender配置示例如下
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>myApp.log</file>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
上面配置定义了两个日志输出器FILE和STDOUT,通过在appender-ref标签中引用名称,将appenders附加到根日志记录器。FILE的作用是输出debug级别的日志到名为myApp.log的文件(文件不存在时自动创建),STDOUT的作用是输出debug级别的日志到控制台。
注意:每个appender都有自己的编码器。编码器通常不设计为由多个appenders共享。布局也是如此。因此,logback配置文件不提供任何用于共享编码器或布局的语法手段。
默认情况下,appenders是累加的:一个日志记录器(logger)采用一个appender的同时会将这个appender传递给根日志记录器(root)。因此,将相同的appender附加到多个日志记录器会导致日志输出被复制。例如下面:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="chapters.configuration">
<appender-ref ref="STDOUT" />
</logger>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
运行输出日志如下:
14:25:36.343 [main] INFO chapters.configuration.MyApp3 - Entering application.
14:25:36.343 [main] INFO chapters.configuration.MyApp3 - Entering application.
14:25:36.359 [main] DEBUG chapters.configuration.Foo - Did it again!
14:25:36.359 [main] DEBUG chapters.configuration.Foo - Did it again!
14:25:36.359 [main] INFO chapters.configuration.MyApp3 - Exiting application.
14:25:36.359 [main] INFO chapters.configuration.MyApp3 - Exiting application.
可以看到日志输出重复。为防止日志重复输出,我们可以通过配置logger的additivity属性值来控制logger的appender累加到root。当此属性设置为false时,logger的appender将不会累加到root。默认值为true。
additivity=“true”在实际开发中也是很有用的,通过它我们可以将特定的appender日志都输出到控制台。例如:
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>myApp.log</file>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<logger name="chapters.configuration">
<appender-ref ref="FILE" />
</logger>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
logger日志记录器在把日志输出到myApp.log文件中的同时也会把日志打印到控制台。
注意、logger没有定义level时,会默认继承root的level.
- contextName
每个日志记录器都会附加到日志记录器上下文中。默认情况下,logger上下文被称为“default”。但是,您可以在配置contextName设置不同的名称。注意,一旦设置,日志记录器上下文名称不能更改。通过设置logger上下文名称可以区分多个应用程序日志记录到同一个目标中。示例:
<configuration>
<contextName>myAppName</contextName>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d %contextName [%t] %level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
- property
变量可以在配置文件本身中定义一次,也可以从外部属性文件或外部资源中加载。由于历史原因,定义变量的XML元素是<property>
,但在logback 1.0.7之后,也可以通过<variable>
定义变量。示例:
<configuration>
<property name="USER_HOME" value="/home/sebastien" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${USER_HOME}/myApp.log</file>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
</root>
</configuration>
在内部定义变量
<configuration>
<property resource="resource1.properties" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${USER_HOME}/myApp.log</file>
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
</root>
</configuration>
引用外部的属性文件 variables1.properties文件中定义 USER_HOME=/home/sebastien
- encoder
编码器负责将事件转换成字节数组,并将字节数组写入OutputStream。在logback版本0.9.19中引入了编码器。在以前的版本中,大多数appenders依赖于一个布局来将事件转换成字符串,并使用java.io.Writer编写。在以前的logback版本中,用户需要FileAppender内嵌套一个PatternLayout。但从logback 0.9.19之后, 编码器的出现,而不再需要这样做。
目前,PatternLayoutEncoder是唯一真正有用的编码器。但它只是包装了大部分工作的模式布局。编码器似乎并没有给工作带来太多的好处,除了不必要的复杂性。但是,我们希望随着新的和强大的编码器的出现,这种现象将会改变。
为了便于对日志文件进行解析,logback可以在日志顶部插入日志输出的模式。默认情况下禁用此功能。可以通过将outputPatternAsHeader属性设置为“true”来启用相关的PatternLayoutEncoder。示例:
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>foo.log</file>
<encoder>
<pattern>%d %-5level [%thread] %logger{0}: %msg%n</pattern>
<outputPatternAsHeader>true</outputPatternAsHeader>
</encoder>
</appender>
输出:
#logback.classic pattern: %d [%thread] %-5level %logger{36} - %msg%n
2012-04-26 14:54:38,461 [main] DEBUG com.foo.App - Hello world
2012-04-26 14:54:38,461 [main] DEBUG com.foo.App - Hi again
filter
有时候,我们需要在特定的appender中只输出特定级别的日志,此时就需要用到filter。过滤器有很多种,这里只介绍LevelFilter和ThresholdFilter
- LevelFilter
LevelFilter根据精确的级别匹配过滤事件。如果事件的级别等于配置的级别,则根据onMatch和on属性的配置,过滤器接受或拒绝事件。示例:
配置
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger{30} - %msg%n
</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
CONSOLE只会输出info级别的日志
- ThresholdFilter
阈值筛选器将事件过滤到指定的阈值之下。对于级别相等或超过阈值的事件,当调用其decide()方法时,阈值筛选器将保持中立。但是,低于阈值的事件将被拒绝。示例:
<configuration>
<appender name="CONSOLE"
class="ch.qos.logback.core.ConsoleAppender">
<!-- deny all events with a level below INFO, that is TRACE and DEBUG -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger{30} - %msg%n
</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
CONSOLE会输出info、warn、error级别的日志,除了debug
完整配置示例
<?xml version="1.0" encoding="UTF-8" ?>
<!--scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。-->
<!--scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。-->
<!--debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。-->
<configuration scan="true" scanPeriod="60 seconds" debug="true">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<!-- linux -->
<property name="LOG_HOME" value="log" />
<contextName>myAppName</contextName>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/demo.info.%i.log.zip</fileNamePattern>
<!-- each file should be at most 100MB, keep 60 days worth of history, but at most 1GB -->
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
<!--<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">-->
<!--<!–日志文件输出的文件名–>-->
<!--<FileNamePattern>${LOG_HOME}/call-%d{yyyy-MM-dd}.log</FileNamePattern>-->
<!--<!–日志文件保留天数–>-->
<!--<MaxHistory>30</MaxHistory>-->
<!--</rollingPolicy>-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<!--<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">-->
<!--<MaxFileSize>10MB</MaxFileSize>-->
<!--</triggeringPolicy>-->
</appender>
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/call.warn.%i.log</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/%d{yyyy-MM-dd}/call.error.%i.log</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
<logger name="top.fyr.demo" level="INFO" additivity="false" >
<appender-ref ref="INFO_FILE" />
<appender-ref ref="WARN_FILE" />
<appender-ref ref="ERROR_FILE" />
</logger>
<!--myibatis log configure-->
<!--<logger name="com.apache.ibatis" level="TRACE"/>-->
<!--<logger name="java.sql.Connection" level="DEBUG"/>-->
<!--<logger name="java.sql.Statement" level="DEBUG"/>-->
<!--<logger name="java.sql.PreparedStatement" level="DEBUG"/>-->
</configuration>
END
以上就是logback框架的一个大概介绍,还有很多高级特性没有涉及到,有兴趣可以去看logback官网阅读。