学习笔记
〇、大背景
只要使用了lombok
,就引入了 @Slf4j
,也就直接可以使用 log.info() ...
等日志方式了。
具体只是日志往哪里写而已。
所以,只要是一个springboot项目,基本上就是这套日志方案了。
一、 基本
springboot项目启动时,不论是直接使用了 parent
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.1.9.RELEASE</version>
</parent>
还是 只使用了
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.9.RELEASE</version>
</dependency>
都会间接引入 logback-classic,进而可通过 logback.xml的方式配置日志具体输出。
二、具体概念
学习关键词记录(提到这个词,想到用途、含义就已经明白了)
最外层
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
</configuration>
彩色日志渲染
<!-- 彩色日志 -->
<!-- 彩色日志依赖的渲染类 -->
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
<conversionRule conversionWord="wex"
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
<conversionRule conversionWord="wEx"
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
变量property
springProperty
如
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} [%X{out_trace_no}] [%X{INNER_TRACE_ID}] %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!--业务日志输出格式-->
<property name="SERVICE_OUTPUT_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{out_trace_no}] [%X{INNER_TRACE_ID}] [%thread] %-5level %logger{56} - %msg%n"/>
<!--SQL监控日志输出格式-->
<property name="SQL_OUTPUT_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{out_trace_no}] [%X{INNER_TRACE_ID}] [%thread] %-5level %logger{56} - %msg%n"/>
<property name="LOG_LEVEL" value="info"/>
<springProperty scope="context" name="applicationName" source="spring.application.name"/>
<springProperty scope="context" name="env" source="spring.profiles.active"/>
appender
如 STDOUT的appender
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
其他appender
<appender name="ROOT" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${log.path}/root.log</File>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}/root-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
<!-- 单个日志文件最多 100MB, 60天的日志周期,最大不能超过20GB -->
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${SERVICE_OUTPUT_PATTERN}</pattern>
</encoder>
</appender>
<appender name="BIZ" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${log.path}/biz.log</File>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>DENY</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- rollover daily -->
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}/biz-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
<!-- 单个日志文件最多 100MB, 60天的日志周期,最大不能超过20GB -->
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${SERVICE_OUTPUT_PATTERN}</pattern>
</encoder>
</appender>
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${log.path}/error.log</File>
<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">
<!-- rollover daily -->
<fileNamePattern>${log.path}/%d{yyyy-MM-dd}/error-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
<!-- 单个日志文件最多 100MB, 60天的日志周期,最大不能超过20GB -->
<maxFileSize>100MB</maxFileSize>
<maxHistory>60</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>${SERVICE_OUTPUT_PATTERN}</pattern>
</encoder>
</appender>
encoder:日志文件输出格式;
file:日志输出路径及文件名;
rollingPolicy:日志滚动策略,例子中配置为按照时间滚动;
fileNamePattern:滚动日志文件路径及文件名配置;
maxFileSize:最大日志文件大小;
maxHistory:日志文件最大保留天数;
此处注意一下,<filter>
有意思。
filter:日志过滤器,在appender中配置,有 三个返回值,分别是deny,neutral,accept。
返回deny,表示日志将立即被抛弃;
返回neutral,表示进入到下一个过滤器中进行处理;
返回accept,日志会被立即处理,不再经过剩余过滤器,如果appender中有多个过滤器则按照顺序依次进行处理;
levelFilter:级别过滤器,该过滤器有三个子节点器:level、onMatch、OnMismatch。
它会根据onMatch 和 onMismatch选择接收或拒绝日志,但该过滤器只会过滤出刚好符合日志级别的日志。
此外还有一个过滤器为ThresholdFilter
,这个过滤器会过滤掉低于指定临界值的日志,当日志级别等于或高于临界值时,过滤器返回NEUTRAL;当日志级别低于临界值时,日志会被拒绝;
logger
比如随便写一个logger
<logger name="com.mysite.logback.demo.controller" additivity="false">
<level value="INFO"/>
<appender-ref ref="STDOUT"/>
<appender-ref ref="BIZ"/>
<appender-ref ref="ERROR"/>
</logger>
logger
仅有一个name属性,一个可选的level和一个可选的addtivity属性。
name:用来指定受此loger约束的某一个包或者具体的某一个类。
可以用这个来使得不同包的日志写到不同地方去。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。
如果未设置此属性,那么当前loger将会继承上级的级别。
addtivity: 是否向上级loger传递打印信息。默认是true。
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
root
也是元素,但是它是根logger。只有一个level属性,因为已经被命名为"root".
additivity=“true” 的<logger>
的日志会再输出到root中去。
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能设置为INHERITED或者同义词NULL。
默认是DEBUG。
可以包含零个或多个<appender-ref>
元素,标识这个appender将会添加到这个logger。
三、进阶
4.1 动态配置(表达式)
xml里面其实是可以写表达式的。
如:
<root level="info">
<if condition='"${log.console.open}".equals("true")'>
<then>
<appender-ref ref="STDOUT" />
<appender-ref ref="commonAsync" />
</then>
<else>
<appender-ref ref="ERROR" />
<appender-ref ref="ROOT" />
<appender-ref ref="commonAsync" />
</else>
</if>
</root>
4.2 异步appender的用法
直接示例:
<appender>
<!-- 增加发送日志到kafka相关的配置 -->
<appender name="CommonAppender" class="cn.xuetian.framework.logs.es.appender.CommonAppender">
<!-- 临界值过滤器,打印指定级别以上的日志-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>${LOG_LEVEL}</level>
</filter>
<bootstrapServers>1.2.3.4:9092,1.2.3.5:9092,1.2.3.6:9092</bootstrapServers>
<userName>kafka</userName>
<password>xxxxxxx</password>
<applicationName>${applicationName}</applicationName>
<env>${env}</env>
</appender>
<appender name="commonAsync" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold>
<queueSize>100</queueSize>
<neverBlock>true</neverBlock>
<appender-ref ref="CommonAppender"/>
</appender>
<logger>
(有时候不用异步会启动报错)
<root level="info">
<if condition='"${log.console.open}".equals("true")'>
<then>
<appender-ref ref="STDOUT" />
<appender-ref ref="commonAsync" />
</then>
<else>
<appender-ref ref="ERROR" />
<appender-ref ref="ROOT" />
<appender-ref ref="commonAsync" />
</else>
</if>
</root>
四、项目示例
https://gitee.com/codejam_org/logback-demo