引言
本文将通过介绍logback的常用配置,根据完整的配置文件举例说明每一个标签属性的意义和用法,实现适用生产的日志拆分、日志保存功能,并提供完整的运行过程效果
logback配置标签
先介绍一下logback常用的一些标签,方便大家有个理解,logback常用的配置标签结构大致如下:
configuration标签configuration下有3个配置项
<configuration scan="true" scanPeriod="60 seconds" debug = "true">
scan="true" 表示打开动态加载配置,scanPeriod 用于配置动态加载时间,当不指定scan、scanPeriod时默认scan="true" scanPeriod="60 seconds",配置debug = "true"打开logback的调试日志,默认不打开
property标签property用于声明变量
<property name="CHARSET" value="UTF-8"/>
logback也支持读取spring配置文件中的配置项,可以通过springProperty读取
<springProperty scope="context" name="springAppName"
source="spring.application.name" />
appender标签appender是对日志事件进行输出的组件
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${PATTERN}</pattern>
<charset>${CHARSET}</charset>
</encoder>
</appender>
常用的appender有:
ConsoleAppender 将日志事件附加到控制台
FileAppender 将日志事件输出到文件中
RollingFileAppender 轮转日志文件,当日志文件满足条件后,将日志输出到另外一个文件
logger标签
logger用来设置某个包或者某个类的级别以及指定appender
<logger name="errorLogger" additivity ="true" level="ERROR">
<appender-ref ref="errorAppender" />
</logger>
additivity声明向上级logger传递打印信息,默认是true;appender-ref指定日志输出的组件,可以配置多个
root标签
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
root标签是所有logger的上级,如果下级appender指定了additivity="true",下级appender的输出都会在root中声明的appender中体现
实践
直接上一个完整可用配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProperty scope="context" name="springAppName"
source="spring.application.name" />
<springProperty scope="context" name="springActive"
source="spring.profiles.active" />
<property name="CHARSET" value="UTF-8"/>
<property name="SAVE_PATH" value="/data/logs/${springAppName}"/>
<property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %X{trackId} [%15.15t] %class{39}.%method[%L] : %m%n"/>
<if condition='property("springActive").equals("prod")'>
<then>
<property name="maxHistory" value="7"/>
</then>
<else>
<property name="maxHistory" value="3"/>
</else>
</if>
<property name="maxFileSize" value="200MB"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${PATTERN}</pattern>
<charset>${CHARSET}</charset>
</encoder>
</appender>
<appender name="digestAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<file>${SAVE_PATH}/${springAppName}-digest.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${SAVE_PATH}/digest/${springAppName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
<append>true</append>
</appender>
<appender name="bizAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<file>${SAVE_PATH}/${springAppName}-biz.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${SAVE_PATH}/biz/${springAppName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
<append>true</append>
</appender>
<appender name="statAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<file>${SAVE_PATH}/${springAppName}-stat.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${SAVE_PATH}/stat/${springAppName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${PATTERN}</pattern>
<charset>${CHARSET}</charset>
</encoder>
<append>true</append>
</appender>
<appender name="errorAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${SAVE_PATH}/${springAppName}-error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${SAVE_PATH}/error/${springAppName}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>${maxHistory}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${maxFileSize}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${PATTERN}</pattern>
<charset>${CHARSET}</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<append>true</append>
</appender>
<logger name="digestLogger" additivity ="true">
<appender-ref ref="digestAppender" />
</logger>
<logger name="bizLogger" additivity ="true">
<appender-ref ref="bizAppender" />
</logger>
<logger name="statLogger" additivity ="true">
<appender-ref ref="statAppender" />
</logger>
<logger name="errorLogger" additivity ="true" level="ERROR">
<appender-ref ref="errorAppender" />
</logger>
<logger name = "cn.sleeper" level = "DEBUG"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
解释
如上配置
-
springProperty从spring配置文件中获取了应用名用以对日志的命名,获取了spring.profiles.active参数用于区分运行环境 -
property定义了CHARSET用于指定日编码、定义SAVE_PATH用于指定日志文件的报存路径、定义PATTERN指定日志格式、定义maxHistory声明日志文件保持天数、maxFileSize指定每个日志文件的最大容量,需要一提的是,logback中使用<if condition...判断,需要添加janino依赖,参考如下:<dependency> <groupId>org.codehaus.janino</groupId> <artifactId>janino</artifactId> <version>2.6.1</version> </dependency> -
appender
(1)STDOUTappender类型为ConsoleAppender,作为控制台输出,指定控制台输出日志格式、编码类型
(2)bizAppenderappender类型为RollingFileAppender,作为业务日志输出
(3)digestAppenderappender类型为RollingFileAppender,作为摘要日志输出
(4)statAppenderappender类型为RollingFileAppender,作为统计日志输出
(5)errorAppenderappender类型为RollingFileAppender,作为异常日志输出
在以上每个appender定义了<level>日志打印级别,使用TimeBasedRollingPolicy定义日志文件的轮转策略,指定了日志文件命名、最长保存时间、文件最大容量,使用<encoder>定义日志格式、日志编码,errorAppender使用LevelFilter过滤ERROR级别的日志,所有ERROR级别的日志交给errorAppender处理,非INFO级别的日志会被过滤掉,其他appender使用ThresholdFilter过滤低于配置值INFO级别的日志 -
logger
针对每一个定义的appender,定义了对应的logger,使用appender-ref关联,便于在代码中进行日志拆分,additivity="true"表示日志会反馈到root中,root中定义的是控制台输出的appender,也就是说在logger声明了additivity="true",不仅会被<logger>本身到appender记录到文件中,也会打印到控制台 -
root
level定义了打印级别appender-ref指定了输出到控制台到ConsoleAppender
效果
结合上面的配置文件,我们定义了多个logger,所以在使用的时候,需要对log进行一层封装,以便在调用的时候能够调用定义好的对应的appender组件
public interface LogApi {
Logger dlog = LoggerFactory.getLogger("digestLogger");
Logger blog = LoggerFactory.getLogger("bizLogger");
Logger slog = LoggerFactory.getLogger("statLogger");
Logger elog = LoggerFactory.getLogger("errorLogger");
}
使用LogApi打印日志测试
@RestController
@RequestMapping("/test")
public class LogController {
@GetMapping
public void log() {
blog.trace("测试业务日志 trace");
blog.debug("测试业务日志 debug");
blog.info("测试业务日志 info");
blog.warn("测试业务日志 warn");
blog.error("测试业务日志 error");
elog.trace("测试异常日志 trace");
elog.debug("测试异常日志 debug");
elog.info("测试异常日志 info");
elog.warn("测试异常日志 warn");
elog.error("测试异常日志 error");
slog.trace("测试统计日志 trace");
slog.debug("测试统计日志 debug");
slog.info("测试统计日志 info");
slog.warn("测试统计日志 warn");
slog.error("测试统计日志 error");
dlog.trace("测试摘要日志 trace");
dlog.debug("测试摘要日志 debug");
dlog.info("测试摘要日志 info");
dlog.warn("测试摘要日志 warn");
dlog.error("测试摘要日志 error");
}
}
控制台输出效果
生成的目录结构
biz目录下
为了测试,定义了2KB拆分,所以当文件大于2kb,将会放到配置的目录中去,生成新的文件
logTest-biz.log
logTest-error.log
本例代码已上传 github.com/chenxuancod…