这篇文章给大家介绍springboot项目使用日志工具Logback把日志输出到控制台,输出到文件的具体方法;介绍了Logback的xml配置文件中各个标签的具体内容;列出了常见的配置文件内容。
Logback简介:Logback是一个开源的日志组件,师出同门,与log4j一样,logback也是由Ceki Gülcü开发的开源日志组件,可以说是log4j的改进版;在现如今的项目中,logback的出现次数越来越多,是目前主流首选的日志记录工具。
logback分成三个模块:logback-core,logback- classic,logback-access(这个不常用)。
1.Logback日志组件各个模块的功能
- logback-core:提供了LogBack的核心功能,是另外两个组件的基础。
- logback-classic:实现了Slf4j的API,所以当想配合Slf4j使用时,需要引入logback-classic。
什么是Slf4j:简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,它只服务于各种各样的日志系统。在使用SLF4J的时候,不需要在代码中或配置文件中指定你打算使用那个具体的日志系统。
- logback-access:为了集成Servlet环境而准备的,可提供HTTP-access的日志接口。
2.Logback日志组件各个模块的maven依赖
<!-- logback -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>${logback.version}</version>
</dependency>
3.项目启动时Logback日志配置文件扫描规则
启动项目时,logback会按照如下顺序扫描配置文件:
- 在系统配置文件System Properties中寻找是否有logback.configurationFile对应的value
- 在classpath下寻找是否有logback.groovy(即logback支持groovy与xml两种配置方式)
- 在classpath下寻找是否有logback-test.xml
- 在classpath下寻找是否有logback.xml
以上任何一项找到了,就不进行后续扫描,按照对应的配置进行logback的初始化,可从控制台输出信息中查看加载的配置文件。
当所有以上四项都找不到的情况下,logback会调用ch.qos.logback.classic.BasicConfigurator的configure方法,构造一个ConsoleAppender用于向控制台输出日志,默认日志输出格式为%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n。
在Springboot项目中可以自定义logback配置文件名及文件位置
要想让Springboot项目识别到该logback配置文件,只需要在Springboot配置文件中定义好配置文件的加载路径即可如下所示:
4.Logback具体可实现的功能
- 自动重新加载配置文件
当配置文件修改了,Logback-classic能自动重新加载配置文件。扫描过程快且安全,它并不需要另外创建一个扫描线程。 - 自动去除旧的日志文件
通过设置TimeBasedRollingPolicy或者SizeAndTimeBasedFNATP的maxHistory属性,你可以控制已经产生日志文件的最大数量。如果设置maxHistory 12,那那些log文件超过12个月的都会被自动移除。 - 堆栈树带有包版本
Logback在打出堆栈树日志时,会带上包的数据。 - 自动压缩已经打出来的log
RollingFileAppender在产生新文件的时候,会自动压缩已经打出来的日志文件。压缩是个异步过程,所以甚至对于大的日志文件,在压缩过程中应用不会受任何影响。
5.Logback配置文件详解
- 根节点<configuration>
<!-- 输出logback内部日志信息,每隔30s判断一下配置文件有没有更新,若更新,则重新加载 -->
<configuration scan="true" scanPeriod="30 seconds" debug="true">
<!--
scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
- 设置变量<property>
<configuration>
<!-- 定义日志文件的存储地址 -->
<property name="LOG_HOME" value="log"/>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度 %msg:日志消息,%n是换行符-->
<property name="LOG_PATTERN" value="%d{yyyyMMdd:HH:mm:ss.SSS} [%thread] %-5level %msg%n"/>
</configuration>
<!--
name:变量的名称,可以随意起名,但建议名字要简明直译;
value:变量的值;
在配置文件中,我们可以用 ${} 的方式来使用,将变量引入到其他节点中去。
-->
- <appender>
负责写日志的组件,有两个必要属性name和class
- 常用的控制台输出:ConsoleAppender
<!-- name指定<appender>的名称
class指定<appender>的全限定名 -->
<!-- 控制台输出 appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- <encoder>表示输出格式 -->
<pattern>${LOG_PATTERN}</pattern>
<!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
<charset>utf8</charset>
</encoder>
</appender>
- 常用的滚动记录文件:RollingFileAppender
<!-- INFO日志 appender: 按照每天生成日志文件 -->
<appender name="INFO-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 过滤器,只记录 info 级别以上的日志 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
<file>${LOG_HOME}/iot-sdk-info.log</file>
<!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件输出的文件名:
%d:可以包含一个Java.text.SimpleDateFormat指定的时间格式
%i:自增数字
-->
<fileNamePattern>${LOG_HOME}/iot-sdk-info.%d{yyyy-MM-dd}.%i.log.zip</fileNamePattern>
<!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
<maxHistory>30</maxHistory>
<!-- 文件大小超过100MB归档 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
4.<encoder>
encoder节点负责两件事情:
- 把日志信息转换为字节数组
- 把字节数组写到输出流
以下是一个常用配置:
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 用来设置日志的输入格式,使用“%+转换符”的方式,如果要输出”%”则必须使用”\”进行转义。-->
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!-- 格式化输出:https://logback.qos.ch/manual/layouts.html
%d 表示日期,
%thread 表示线程名,
%level 日志级别从左显示5个字符宽度,
%t 线程名
%file:%line 文件名+行号,
%m 日志消息,%n是换行符
%X{traceId}:自定义设置的参数,后面会说。
-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %t %file:%line %X{traceId} -| %m%n</pattern>
<charset>utf8</charset>
</encoder>
</appender>
5.<filter>
配合appender使用,<filter>是<appender>的一个子节点,表示在当前给到的日志级别下再进行一次过滤
- Level 级别过滤器
根据日志级别进行过滤。如果日志级别等于配置级别,过滤器会根据onMath和onMismatch接收(ACCEPT)或拒绝(DENY)日志。
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 只记录error级别的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
- ThresholdFilter: 临界值过滤器
将日志级别低于<level>的全部进行过滤。当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝。
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- 记录info级别以上的日志 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
- <logger>与<root>
<logger>用来设置某一个包或者具体某一个类的日志打印级别、以及指定appender。
<logger>可以包含零个或者多个<appender-ref>元素,标识这个appender将会添加到这个logger。
<root>也是<logger>元素,但它是根logger,只有一个level属性,因为它的name就是ROOT
<!-- name:必填,指定受此logger约束的某一个包或者具体的某一个类。这个name表示的是LoggerFactory.getLogger(XXX.class),XXX的包路径,包路径越少越是父级
level:用来设置打印级别,五个常用打印级别从低至高依次为TRACE、DEBUG、INFO、WARN、ERROR,如果未设置此级别,那么当前logger会继承上级的级别
additivity:是否向上级logger传递打印信息,默认为true -->
<logger name="com.example.iot" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-APPENDER"/>
<appender-ref ref="ERROR-APPENDER"/>
</logger>
<!-- 没有配置<appender-ref>,表示此<logger>不会打印出任何信息 -->
<logger name="com.example.iot.demo1" level="DEBUG" additivity="true" />
<!-- 没有配置level,即继承父级的level,<logger>的父级为<root>,那么level=info -->
<logger name="com.example.iot.demo2" additivity="false" />
<!-- 控制台输出日志级别 -->
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
6.Logback日志常用配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds" debug="true">
<!-- logback的根节点 <configuration>的属性scan、scanPeriod、debug
scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod: 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug: 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<!-- 定义日志文件的存储地址 -->
<property name="LOG_HOME" value="log"/>
<!-- 格式化输出:
%d 表示日期,
%thread 表示线程名,
%level 日志级别从左显示5个字符宽度,
%thread 线程名
%file:%line 文件名:行号,
%m 日志消息,
%n 换行符,
%X{traceId} 自定义设置的参数
%mdc 自定义参数
-->
<property name="LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%5level) -- [%15.15t] %cyan(%-23.23logger{23}) : %m%n"/>
<!-- appender是configuration的子节点,是负责写日志的组件 -->
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
<charset>utf8</charset>
</encoder>
</appender>
<!-- INFO日志 appender: 按照每天生成日志文件 -->
<appender name="INFO-APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 过滤器,记录info级别以上的日志 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<!-- 写入的日志文件名,可以使相对目录也可以是绝对目录,如果上级目录不存在则自动创建 -->
<file>${LOG_HOME}/iot-sdk-info.log</file>
<!-- 如果为true表示日志被追加到文件结尾,如果是false表示清空文件 -->
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件输出的文件名: %d可以包含一个Java.text.SimpleDateFormat指定的时间格式 -->
<fileNamePattern>${LOG_HOME}/iot-sdk-info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 日志文件保存历史数量:控制保留的归档文件的最大数量,如果超出数量就删除旧文件 -->
<maxHistory>30</maxHistory>
<!-- 文件大小超过100MB归档 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- 错误日志 appender: 按照每天生成日志文件 -->
<appender name="ERROR-APPENDER" 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>
<!-- 日志名称 -->
<file>${LOG_HOME}/iot-sdk-error.log</file>
<append>true</append>
<!-- 每天生成一个日志文件,保存30天的日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件输出的文件名:按天回滚 daily -->
<fileNamePattern>${LOG_HOME}/iot-sdk-error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 日志文件保留天数 -->
<maxHistory>30</maxHistory>
<!-- 文件大小超过100MB归档 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
<!-- 指定项目中某个包,当有日志操作行为时的日志记录级别
级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE
additivity=false 表示匹配之后,不再继续传递给其他的logger
-->
<logger name="com.example.iot" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-APPENDER"/>
<appender-ref ref="ERROR-APPENDER"/>
</logger>
<!-- 控制台输出日志级别 -->
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
7.Logback高级特性异步输出日志
之前的日志配置方式是基于同步的,每次日志输出到文件都会进行一次磁盘IO。采用异步写日志的方式而不让此次写日志发生磁盘IO,阻塞线程从而造成不必要的性能损耗。异步输出日志的方式很简单,添加一个基于异步写日志的appender,并指向原先配置的appender即可。
logback AsyncAppender 目前在logback 1.0.11及以上版本存在
示例:
<!-- 异步输出 -->
<appender name="ASYNC-INFO-APPENDER" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>256</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="INFO-APPENDER"/>
</appender>
<appender name="ASYNC-ERROR-APPENDER" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>256</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="ERROR-APPENDER"/>
</appender>
<!-- 设置开发环境日志级别为INFO(采用异步输出的方式) -->
<!-- springProfile 标签下面会讲 -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="ASYNC-INFO-APPENDER"/>
</root>
</springProfile>
8.Logback配置文件与Springboot配置文件的配合
1.springProfile标签,可实现根据不同的springboot配置文件进行不同级别的日志打印
该 <springProfile> 标签允许我们更加灵活配置文件,可选地包含或排除配置部分。元素中的任何位置均支持轮廓部分。使用该name属性指定哪个配置文件接受配置。可以使用逗号分隔列表指定多个配置文件。
<springProfile name="dev">
<!-- 开发环境时激活 -->
</springProfile>
<springProfile name="dev,test">
<!-- 开发,测试的时候激活-->
</springProfile>
<springProfile name="!prod">
<!-- 当 "生产" 环境时,该配置不激活-->
</springProfile>
- 案例
<!-- 开发环境日志级别为DEBUG -->
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-APPENDER"/>
</root>
</springProfile>
<!-- 测试环境日志级别为INFO -->
<springProfile name="test">
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-APPENDER"/>
</root>
<!-- 生产环境日志级别为INFO -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO-APPENDER"/>
</root>
</springProfile>
2.springProperty
该 <springProperty> 标签允许我们从Spring中显示属性,Environment 以便在Logback中使用。如果你想将 application.properties在回读配置中访问文件中的值,这将非常有用。
标签的工作方式与Logback的标准 <property> 标签类似,但不是直接value 指定source属性(从Environment)指定。scope 如果需要将属性存储在local范围之外的其他位置,则可以使用该属性。如果您需要一个后备值,以防该属性未设置,则Environment可以使用该defaultValue属性。
<!-- 从Spring环境变量中获取值, source属性是springboot配置文件中的key -->
<springProperty scope="context" name="LOGBACK_NAME" source="springboot.application.name" defaultValue="appName"/>
<!-- 应用 通过${name}引入-->
<appender name="EXAMPLE" class="ch.qos.logback.more.appenders.EXAMPLEAppender">
<remoteHost>${LOGBACK_NAME}</remoteHost>
</appender>