logback官方文档 logback的配置和使用
本文大部分来自于官网文档,logback官方文档:https://logback.qos.ch/manual/introduction.html
logback作为log4j的改进版,所有在使用上和log4j也很相似,由三个模块组成:
logback-core:其它两个模块的基础模块
logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API使你可以很方便地更换成其它日志系统如log4j或JDK14 Logging
logback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能
通常我们只需要使用logback-core和logback-classic即可。
Logger, Appenders and Layouts
logback的三个主要组成为Logger, Appenders and Layouts,和log4j一样。Logger包含在loback-classic里面,而Appender和Layout则是在logback-core里面。
Logger 作为日志的记录器,把它关联到应用的对应的context上后,主要用于存放日志对象,也可以定义日志类型、级别。
Appender 主要用于指定日志输出的目的地,目的地可以是控制台、文件、远程套接字服务器、 MySQL、PostreSQL、 Oracle和其他数据库、 JMS和远程UNIX Syslog守护进程等。
Layout 负责把事件转换成字符串,格式化的日志信息的输出。
Logger:
和log4j一样,大小写敏感,具有父子关系,通过"."来实现。比如com.foo就是com.foo.test的父Logger。
rootLogger是Logger的顶级父Logger,所有的Logger都是他的子集。
可以通过Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);获取rootLogger。
Level:
Logger的级别定义在ch.qos.logback.classic.Level里面,按照等级从高往低排列如下:
OFF > ERROR > WARN > INFO > DEBUG > TRACE > ALL。
如果一个Logger没有指定Level,那么他会继承他的父Logger的Level,如果没有那么就直接继承rootLogger的Level。比如com.foo.test会继承com.foo,如果没有那么就找com,还是没有就直接继承rootLogger中指定的Level。
为了确保每个Logger最终都会有一个Level,一般会指定rootLogger的Level,默认为DEBUG级别。
只有当我们调用的打印方法的等级大于或等于该Logger指定的等级的时候才会打印。比如:XXX.info()只有在XXX的Logger的等级在info和info之上时才会打印。
Logger的获取:
我们通过org.slf4j.LoggerFactory 的getLogger()来获取Logger,getLogger的参数就是这个Logger的名字,如果传入的参数相同,那么和Logger4j一样,我们将会获取到同一个Logger对象。
Logger的参数名字是可以自由指定的,但是通常,我们建议使用Logger所在类的class来命名这个Logger。
Appender:
Appender用来指定Log的输出目的地。目前appender支持输出到Console, file, remote socket servers, Mysql, JMS等等。
一个Logger可以指定多个Appender,和log4j一样。一个Logger的输出会输出到他的所有Appender中包括他的父Logger的Appender。比如rootLogger指定了一个Console的Appender,那么所有的Logger都会输出到Console。
Appender都是继承自ch.qos.logback.core.Appender。
下面介绍一些常用的appender:
OutputStreamAppender:
这个其实不常用,但是他是ConsoleAppender,FileAppender 的父 类,所以先介绍一个他。他有两个属性encoder,immediateFlush。encoder默认为PatternLayoutEncoder用于格式化输出,后面会介绍 。immediateFlush默认为true,作用是指定log立即输出到目的地中。outputStreamAppender的继承关系图如下:
可以看到常用的ConsoleAppender,FileAppender和RollingFileAppender都是他的子类,所以我们先介绍了他。
ConsoleAppender:
通过System.out或者System.error将日志打印到控制台。他的主要属性是target,用来指定输出到System.out或者System.error,默认为System.out。
示例:
<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:
输出log到文件中。通过file属性决定输出到哪个文件中,通过append属性决定当文件存在时是追加输出日志,还是删掉旧文件重新生成一个输出日志。
示例:
<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>
独特的文件名(根据timestamp):
如果我们想要根据项目的启动时间命名文件,我们可以使用 <timestamp> 来完成。
示例:
<configuration>
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!-- 使用上面的bySecond属性命令文件 -->
<file>log-${bySecond}.txt</file>
<encoder>
<pattern>%logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
<timestamp>有几个属性,上面的KEY指定这个timestamp的名字为bySecond,datePattern用来格式化时间,规则按照SimpleDateFormat来。
RollingFileAppender:
是FileAppender的子类,指定日志输出到文件,不过他可以配置按照某种规则备份之前输出的日志的文件,然后重新生成一个文件输出新的日志。
RollingFileAppender有两个主要的组成:
RollingPolicy:
当发生滚动时,决定RollingFileAppender的行为,涉及文件移动和重命名。属性class定义具体的滚动策略类。
ch.qos.logback.core.rolling.TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。有以下子节点:
fileNamePattern:必要节点,包含文件名及“%d”转换符,“%d”可以包含一个java.text.SimpleDateFormat指定的时间格式,如:%d{yyyy-MM}。如果直接使用 %d,默认格式是 yyyy-MM-dd。RollingFileAppender的file字节点可有可无,通过设置file,可以为活动文件和归档文件指定不同位置,当前日志总是记录到file指定的文件(活动文件),活动文件的名字不会改变;
如果没设置file,活动文件的名字会根据fileNamePattern 的值,每隔一段时间改变一次。“/”或者“\”会被当做目录分隔符。
maxHistory:日志最大保存的日期。比如如果你设置的pattern是按天算的,那么设置maxHistory为30,那么会自动删除30天之前的日志。
totalSizeCap:日志最大保存的大小。当超过该值,会自动删除老的日志文件。必须和maxHistory一起使用,而且maxHistory先生效,其次是判断是否达到totalSizeCap。
cleanHistoryOnStart:默认false。如果设置为true,再项目启动的时候会自动删除老的日志文件。
triggeringPolicy:
告知 RollingFileAppender 什么时候激活滚动。
ch.qos.logback.core.rolling.FixedWindowRollingPolicy 根据固定窗口算法重命名文件的滚动策略。有以下子节点:
minIndex:窗口索引最小值
maxIndex:窗口索引最大值,当用户指定的窗口过大时,会自动将窗口设置为12。
fileNamePattern:必须包含“%i”例如,假设最小值和最大值分别为1和2,命名模式为 mylog%i.log,会产生归档文件mylog1.log和mylog2.log。还可以指定文件压缩选项,例如,mylog%i.log.gz。
示例:
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE" />
</root>
</configuration>
备注:上述配置表示每天生成一个日志文件,文件名为logFile.yyyy-MM-dd.log,保存30天的日志文件
Encoder:
和layout一样,用来格式化输出。Encoder是在0.9.19版本之后的logback引入的。在这个版本之前,大部分的appender使用layout来格式化输出,但之后FileAppender和他的子类推荐使用encoder来代替layout。
常用的是PatternLayoutEncoder,前面我们也介绍了,这是默认的encoder,所以我们不用指定,直接使用<encoder>标签就好了。
PatternLayoutEncoder的组成和layout一样,如下:
Conversation Word | Effect |
---|---|
%c{length} , %lo{length}, %logger{length} | 打印logger的名字。length不给,输出logger全名。 |
%C{length}, %class{length} | 打印调用logger的类的全名。length不给,打印全类名。 |
%d{pattern} , %date{pattern} , %d{pattern, timezone} , %date{pattern, timezone} | 日志打印的时间,pattern按照simpledateformat的格式,默认yyyy-MM-dd hh:mm:ss,SSS。第二个参数是时区。例如%date{HH:mm:ss.SSS, Australia/Perth} |
%F ,%file | 打印调用logger的java源码文件名,速度不快,避免使用。 |
%L , %line | 打印输出log的行数。 |
%m , %msg , %message | 打印logger输出的日志信息,就是调用logger的方法的时候传入的log字符串。 |
%M , %method | 打印调用该logger的方法名。 |
%n | 换行符 |
%p , %le , %level | 打印该日志的等级 |
%t , %thread | 打印线程名 |
\% | 打印%号 |
格式化修饰器:可以限制上面的ConversationWord的宽度和左右对齐。
比如:
Conversation Word | Effect |
---|---|
%20logger | 最小宽度20,当小于20时右对齐 |
%-20logger | 最小宽度20,当小于20时左对齐 |
%.30logger | 最大宽度30,当logger名大于30的时候会从开始处开始阶段。 |
%20.30logger | 最小20,最大30,小于20的时候右对齐,大于30的时候开始处截断 |
%-20.30logger | 最小20,最大30,小于20的时候左对齐,大于30的时候开始处截断 |
%.-30logger | 最大30,超出时从末尾开始截断。 |
Layout:
Layout的作用是指定日志的输出格式。因为一般使用的都是encoder,所以就不介绍了。
Filter:
过滤器,执行一个过滤器会有返回个枚举值,即DENY,NEUTRAL,ACCEPT其中之一。
返回DENY,日志将立即被抛弃不再经过其他过滤器;
返回NEUTRAL,有序列表里的下个过滤器过接着处理日志;
返回ACCEPT,日志会被立即处理,不再经过剩余过滤器。
过滤器被添加到<appender> 中,为<appender> 添加一个或多个过滤器后,可以用任意条件对日志进行过滤。 有多个过滤器时,按照配置顺序执行。
下面是几个常用的过滤器 :
LevelFilter :
级别过滤器,根据日志级别进行过滤。如果日志级别等于配置级别,过滤器会根据 onMath 和 onMismatch 接收或拒绝日志。
有以下子节点 :
<level> : 设置过滤级别。
<onMatch> : 用于配置符合过滤条件的操作。
<onMismatch> : 用于配置不符合过滤条件的操作。
例如:将过滤器的日志级别配置为info,所有info级别的日志交给appender处理,非info级别的日志,被过滤掉。
XML :
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="contextName" value="limeLog"/>
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HH:mm:ss"/>
<contextName>${contextName} - ${bySecond}</contextName>
<!-- 表示打印到控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 过滤调除了info以外的日志,只打印info的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>info</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<!-- encoder 默认配置为PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<target>System.err</target>
</appender>
<logger name="limeLogback.LogbackDemo" level="debug">
<appender-ref ref="STDOUT"/>
</logger>
<root/>
</configuration>
ThresholdFilter :
临界值过滤器,过滤掉低于指定临界值的日志。当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝。
有以下子节点 :
<level> : 设置过滤级别。
例如:过滤掉所有低于info级别的日志。
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<property name="contextName" value="limeLog"/>
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HH:mm:ss"/>
<contextName>${contextName} - ${bySecond}</contextName>
<!-- 表示打印到控制台 -->
<appender name="limeFlogger" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>info</level>
</filter>
<!-- encoder 默认配置为PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<target>System.err</target>
</appender>
<logger name="LogbackDemo" level="debug">
<appender-ref ref="limeFlogger"/>
</logger>
<root/>
</configuration>
这样配置之后,虽然LogbackDemo这个logger的日志级别时debug,但是使用了limeFlogger后过滤了info之下的日志,也就是不会打印debug的日志。
实例:
maven依赖:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
</dependencies>
logback.xml配置:
<?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="false">
<!-- 定义日志文件 输入位置 -->
<property name="log_dir" value="logs/" />
<!-- 日志最大的历史 30天 -->
<property name="maxHistory" value="30"/>
<!-- ConsoleAppender 控制台输出日志 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 对日志进行格式化 -->
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger -%msg%n</pattern>
</encoder>
</appender>
<!-- ERROR级别日志 -->
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 过滤器,只记录ERROR级别的日志 -->
<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.TimeBasedRollingPolicy">
<!--日志输出位置 可相对、和绝对路径 -->
<fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/error-log.log</fileNamePattern>
<!-- 最大保存30天-->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<!-- WARN级别日志 appender -->
<appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 过滤器,只记录WARN级别的日志 -->
<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.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/warn-log.log
</fileNamePattern>
<!-- 日志最大的历史 30天 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<!-- INFO级别日志 appender -->
<appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 过滤器,只记录INFO级别的日志 -->
<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.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/info-log.log
</fileNamePattern>
<!-- 日志最大的历史 30天 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<appender name="DruidFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${log_dir}/settle-query.log-druid-%d{yyyy-MM-dd}</FileNamePattern>
<!--日志文件保留天数 -->
<MaxHistory>90</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>
</appender>
<!-- DEBUG级别日志 appender -->
<appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 过滤器,只记录DEBUG级别的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/debug-log.log
</fileNamePattern>
<!-- 日志最大的历史 30天 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<!-- TRACE级别日志 appender -->
<appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 过滤器,只记录ERROR级别的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>TRACE</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 按天回滚 daily -->
<fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/trace-log.log
</fileNamePattern>
<!-- 日志最大的历史 30天 -->
<maxHistory>${maxHistory}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
</encoder>
</appender>
<!-- 指定其他logger的Appender -->
<logger name="org.springframework" value="WARN" />
<logger name="org.apache" value="WARN" />
<logger name="com.netflix" value="WARN" />
<logger name="me.chanjar" value="WARN" />
<logger name="com.ulisesbocchio" value="WARN" />
<logger name="org.hibernate" value="WARN" />
<logger name="com.github.liuweijw" value="INFO" />
<logger name="c.n.discovery" value="WARN" />
<logger name="o.s.c.s" value="WARN" />
<logger name="c.u.j.encryptor" value="WARN" />
<logger name="o.s.boot" value="WARN" />
<!-- 指定druid的日志级别为DEBUG,除了继承rootLogger的appender外,自己还加了DruidFILE -->
<logger name="druid" level="DEBUG">
<appender-ref ref="DruidFILE" />
</logger>
<!-- 指定rootLogger级别 INFO,appender为STDOUT,ERROR,INFO-->
<root level="INFO">
<!-- 控制台输出 -->
<appender-ref ref="STDOUT" />
<!-- 文件输出 -->
<appender-ref ref="ERROR" />
<appender-ref ref="INFO" />
</root>
</configuration>
这个配置之后会在当前目录生成一个logs文件夹,logs文件夹会每天生成一个yyyy-MM-dd命名的文件夹,然后每天的trace,info,warn,error-log.log会生成到对应日期的文件夹下面。