移除logback配置文件,直接在yml文件里配置参数
This commit is contained in:
parent
3b6959d678
commit
42465589cf
@ -1,280 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,比如: 如果设置为WARN,则低于WARN的信息都不会输出 -->
|
||||
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
|
||||
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
|
||||
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
|
||||
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||
<springProperty scope="context" name="app_name" source="spring.application.name"/>
|
||||
<!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
|
||||
|
||||
<!--
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
@Log4j2
|
||||
这里底层会判断日志等级,决定是否执行
|
||||
// 我们只是换成了 Log4j2 API,真正的日志记录还是走的 Logback 框架。没错,这就是 SLF4J 适配的一个好处。
|
||||
log.debug("test{}",() ->{return "sdf";});
|
||||
|
||||
-->
|
||||
|
||||
<contextName>logback</contextName>
|
||||
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
|
||||
<property name="logPath" value="logs/${app_name}"/>
|
||||
<property name="log.max.file.size" value="100MB"/>
|
||||
<property name="log.max.history" value="60"/>
|
||||
<property name="log.total.size" value="3GB"/>
|
||||
|
||||
<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 name="CONSOLE_LOG_PATTERN"
|
||||
value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) [%X{REQUEST_ID}] %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="FILE_LOG_PATTERN"
|
||||
value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} [%X{REQUEST_ID}] ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||
|
||||
<!-- 日志输出的格式-->
|
||||
<!-- <property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t-%L] %-5level %logger{36} %L %M - %msg%xEx%n"/>-->
|
||||
<contextName>logback</contextName>
|
||||
<!--输出到控制台 ConsoleAppender-->
|
||||
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<!--展示格式 layout-->
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<!--正常的info日志文件,输出到文件中-->
|
||||
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
|
||||
所以我们使用下面的策略,可以避免输出 Error 的日志,级别的其它高于DEBUG的-->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!--过滤 info-->
|
||||
<level>INFO</level>
|
||||
<!--匹配到就运行-->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!--没有匹配到就禁止-->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
|
||||
如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
|
||||
的日志改名为今天的日期。即,<File> 的日志都是当天的。-->
|
||||
<File>${logPath}/log_info.log</File>
|
||||
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,
|
||||
以防止日志填满整个磁盘空间-->
|
||||
<FileNamePattern>${logPath}/info/%d{yyyy-MM-dd}/log-info-%i.gz</FileNamePattern>
|
||||
<!--每个日志文件最大100MB,超过就重新生成-->
|
||||
<maxFileSize>${log.max.file.size}</maxFileSize>
|
||||
<!--只保留最近60天的日志-->
|
||||
<maxHistory>${log.max.history}</maxHistory>
|
||||
<!--日志整体最大
|
||||
可选的totalSizeCap属性控制所有归档文件的总大小。当超过总大小上限时,将异步删除最旧的存档。
|
||||
totalSizeCap属性也需要设置maxHistory属性。此外,“最大历史”限制总是首先应用,“总大小上限”限制其次应用。
|
||||
-->
|
||||
<totalSizeCap>${log.total.size}</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<!--日志输出编码格式化-->
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!--正常的warn日志文件,输出到文件中-->
|
||||
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
|
||||
所以我们使用下面的策略,可以避免输出 Error 的日志,级别的其它高于DEBUG的-->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!--过滤 warn-->
|
||||
<level>WARN</level>
|
||||
<!--匹配到就运行-->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!--没有匹配到就禁止-->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<File>${logPath}/log_warn.log</File>
|
||||
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,
|
||||
以防止日志填满整个磁盘空间-->
|
||||
<FileNamePattern>${logPath}/warn/%d{yyyy-MM-dd}/log-warn-%i.gz</FileNamePattern>
|
||||
<!--每个日志文件最大100MB,超过就重新生成-->
|
||||
<maxFileSize>${log.max.file.size}</maxFileSize>
|
||||
<!--只保留最近60天的日志-->
|
||||
<maxHistory>${log.max.history}</maxHistory>
|
||||
<!--日志整体最大
|
||||
可选的totalSizeCap属性控制所有归档文件的总大小。当超过总大小上限时,将异步删除最旧的存档。
|
||||
totalSizeCap属性也需要设置maxHistory属性。此外,“最大历史”限制总是首先应用,“总大小上限”限制其次应用。
|
||||
-->
|
||||
<totalSizeCap>${log.total.size}</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<!--日志输出编码格式化-->
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<!--正常的error日志文件,输出到文件中-->
|
||||
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
|
||||
所以我们使用下面的策略,可以避免输出 Error 的日志,级别的其它高于DEBUG的-->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!--过滤 error-->
|
||||
<level>ERROR</level>
|
||||
<!--匹配到就运行-->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!--没有匹配到就禁止-->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<File>${logPath}/log_error.log</File>
|
||||
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,
|
||||
以防止日志填满整个磁盘空间-->
|
||||
<FileNamePattern>${logPath}/error/%d{yyyy-MM-dd}/log-error-%i.gz</FileNamePattern>
|
||||
<!--每个日志文件最大100MB,超过就重新生成-->
|
||||
<maxFileSize>${log.max.file.size}</maxFileSize>
|
||||
<!--只保留最近60天的日志-->
|
||||
<maxHistory>${log.max.history}</maxHistory>
|
||||
<!--日志整体最大
|
||||
可选的totalSizeCap属性控制所有归档文件的总大小。当超过总大小上限时,将异步删除最旧的存档。
|
||||
totalSizeCap属性也需要设置maxHistory属性。此外,“最大历史”限制总是首先应用,“总大小上限”限制其次应用。
|
||||
-->
|
||||
<totalSizeCap>${log.total.size}</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<!--日志输出编码格式化-->
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<!--开启异步日志记录 异步输出,异步的log片段必须在同步段后面,否则不起作用 -->
|
||||
<appender name="INFO_FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 不丢失日志.默认的:如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志,
|
||||
当队列少于discardingThreshold设置的数量就会丢失 <= info 的日志 -->
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||
<queueSize>1024</queueSize>
|
||||
<!-- 不设置neverBolck的话调用的是put方法是阻塞的,设置为true后调用offer方法是不阻塞的-->
|
||||
<neverBlock>true</neverBlock>
|
||||
<appender-ref ref="INFO_FILE"/>
|
||||
</appender>
|
||||
|
||||
<!--开启异步日志记录 异步输出,异步的log片段必须在同步段后面,否则不起作用 -->
|
||||
<appender name="WARN_FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<queueSize>1024</queueSize>
|
||||
<neverBlock>true</neverBlock>
|
||||
<appender-ref ref="WARN_FILE"/>
|
||||
</appender>
|
||||
|
||||
<!--开启异步日志记录 异步输出,异步的log片段必须在同步段后面,否则不起作用 -->
|
||||
<appender name="ERROR_FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<queueSize>1024</queueSize>
|
||||
<neverBlock>true</neverBlock>
|
||||
<appender-ref ref="ERROR_FILE"/>
|
||||
</appender>
|
||||
|
||||
<!-- 我之前就遇到过很多关于 AsyncAppender 异步日志的坑,这些坑可以归结为三类:
|
||||
记录异步日志撑爆内存;
|
||||
记录异步日志出现日志丢失;
|
||||
记录异步日志出现阻塞。
|
||||
出现这个问题的原因在于,AsyncAppender 提供了一些配置参数,而我们没用对。我们结合相关源码分析一下:
|
||||
includeCallerData 用于控制是否收集调用方数据,默认是 false,此时方法行号、方法名等信息将不能显示(源码第 2 行以及 7 到 11 行)。
|
||||
queueSize 用于控制阻塞队列大小,使用的 ArrayBlockingQueue 阻塞队列(源码第 15 到 17 行),默认大小是 256,即内存中最多保存 256 条日志。
|
||||
discardingThreshold 是控制丢弃日志的阈值,主要是防止队列满后阻塞。默认情况下,队列剩余量低于队列长度的 20%,就会丢弃 TRACE、DEBUG 和 INFO 级别的日志。(参见源码第 3 到 6 行、18 到 19 行、26 到 27 行、33 到 34 行、40 到 42 行)
|
||||
neverBlock 用于控制队列满的时候,加入的数据是否直接丢弃,不会阻塞等待,默认是 false(源码第 44 到 68 行)。这里需要注意一下 offer 方法和 put 方法的区别,当队列满的时候 offer 方法不阻塞,而 put 方法会阻塞;neverBlock 为 true 时,使用 offer 方法。
|
||||
|
||||
我们可以继续分析下异步记录日志出现坑的原因。
|
||||
queueSize 设置得特别大,就可能会导致 OOM。
|
||||
queueSize 设置得比较小(默认值就非常小),且 discardingThreshold 设置为大于 0 的值(或者为默认值),队列剩余容量少于 discardingThreshold 的配置就会丢弃 <=INFO 的日志。这里的坑点有两个。一是,因为 discardingThreshold 的存在,设置 queueSize 时容易踩坑。比如,本例中最大日志并发是 1000,即便设置 queueSize 为 1000 同样会导致日志丢失。二是,[discardingThreshold 参数容易有歧义,它不是百分比,而是日志条数]。对于总容量 10000 的队列,如果希望队列剩余容量少于 1000 条的时候丢弃,需要配置为 1000。
|
||||
neverBlock 默认为 false,意味着总可能会出现阻塞。如果 discardingThreshold 为 0,那么队列满时再有日志写入就会阻塞;如果 discardingThreshold 不为 0,也只会丢弃 <=INFO 级别的日志,那么出现大量错误日志时,还是会阻塞程序。
|
||||
可以看出 queueSize、discardingThreshold 和 neverBlock 这三个参数息息相关,务必按需进行设置和取舍,到底是性能为先,还是数据不丢为先:
|
||||
|
||||
如果考虑绝对性能为先,那就设置 neverBlock 为 true,永不阻塞。
|
||||
如果考虑绝对不丢数据为先,那就设置 discardingThreshold 为 0,即使是 <=INFO 的级别日志也不会丢,但最好把 queueSize 设置大一点,毕竟默认的 queueSize 显然太小,太容易阻塞。
|
||||
如果希望兼顾两者,可以丢弃不重要的日志,把 queueSize 设置大一点,再设置一个合理的 discardingThreshold。
|
||||
-->
|
||||
|
||||
<!--指定最基础的日志输出级别 INFO DEBUG-->
|
||||
<root level="INFO">
|
||||
<!--appender将会添加到这个loger-->
|
||||
<appender-ref ref="consoleLog"/>
|
||||
<appender-ref ref="INFO_FILE_ASYNC"/>
|
||||
<appender-ref ref="WARN_FILE_ASYNC"/>
|
||||
<appender-ref ref="ERROR_FILE_ASYNC"/>
|
||||
</root>
|
||||
|
||||
<!-- 定义指定package的日志级别 logger 标签中 .* 无效-->
|
||||
<!-- <logger name="org.springframework" level="DEBUG"/>-->
|
||||
<!-- <logger name="org.mybatis" level="DEBUG"/>-->
|
||||
<!-- <logger name="java.sql.Connection" level="DEBUG"/>-->
|
||||
<!-- <logger name="java.sql.Statement" level="DEBUG"/>-->
|
||||
<!-- <logger name="java.sql.PreparedStatement" level="DEBUG"/>-->
|
||||
<!-- <logger name="io.lettuce.*" level="INFO"/>-->
|
||||
<!-- <logger name="io.netty.*" level="ERROR"/>-->
|
||||
<!-- <logger name="com.rabbitmq.*" level="DEBUG"/>-->
|
||||
<!-- <logger name="org.springframework.amqp.*" level="DEBUG"/>-->
|
||||
<!-- <logger name="org.springframework.scheduling.*" level="DEBUG"/>-->
|
||||
<!-- <logger name="org.springframework.scheduling.*" level="DEBUG"/>-->
|
||||
|
||||
|
||||
<!-- 4 最终的策略:
|
||||
基本策略(root级) + 根据profile在启动时, logger标签中定制化package日志级别(优先级高于上面的root级)-->
|
||||
<!-- <springProfile name="dev">-->
|
||||
<!-- <root level="info">-->
|
||||
<!-- <appender-ref ref="CONSOLE" />-->
|
||||
<!-- <appender-ref ref="DEBUG_FILE" />-->
|
||||
<!-- <appender-ref ref="INFO_FILE" />-->
|
||||
<!-- <appender-ref ref="WARN_FILE" />-->
|
||||
<!-- <appender-ref ref="ERROR_FILE" />-->
|
||||
<!-- <appender-ref ref="ALL_FILE" />-->
|
||||
<!-- </root>-->
|
||||
<!-- <logger name="com.xusanduo.demo" level="debug"/> <!– 开发环境, 指定某包日志为debug级 –>-->
|
||||
<!-- </springProfile>-->
|
||||
|
||||
<!--定义com.xxx..xx..xx包下的日志信息不上传,直接输出到fileDEBUGLog和fileErrorLog这个两个appender中,日志级别为DEBUG-->
|
||||
<!-- <logger name="com.xxx.xxx.xx" additivity="false" level="DEBUG">-->
|
||||
<!-- <appender-ref ref="fileDEBUGLog"/>-->
|
||||
<!-- <appender-ref ref="fileErrorLog"/>-->
|
||||
<!-- </logger>-->
|
||||
|
||||
<!--
|
||||
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、
|
||||
以及指定<appender>。<logger>仅有一个name属性,
|
||||
一个可选的level和一个可选的addtivity属性。
|
||||
name:用来指定受此logger约束的某一个包或者具体的某一个类。
|
||||
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
|
||||
还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。
|
||||
如果未设置此属性,那么当前logger将会继承上级的级别。
|
||||
addtivity:是否向上级logger传递打印信息。默认是true。
|
||||
<logger name="org.springframework.web" level="info"/>
|
||||
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
|
||||
-->
|
||||
|
||||
<!--
|
||||
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
|
||||
第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
|
||||
第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
|
||||
【logging.level.org.mybatis=debug logging.level.dao=debug】
|
||||
<logger name="xxxx.xx.dao" level="DEBUG"/>
|
||||
指定到mapper.xml对应的dao所在的包。
|
||||
-->
|
||||
|
||||
<!--
|
||||
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
|
||||
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
|
||||
不能设置为INHERITED或者同义词NULL。默认是DEBUG
|
||||
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
|
||||
-->
|
||||
|
||||
</configuration>
|
@ -1,267 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,比如: 如果设置为WARN,则低于WARN的信息都不会输出 -->
|
||||
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
|
||||
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
|
||||
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
|
||||
<configuration scan="true" scanPeriod="60 seconds" debug="false">
|
||||
<springProperty scope="context" name="app_name" source="spring.application.name" />
|
||||
<!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
|
||||
|
||||
<contextName>logback</contextName>
|
||||
<!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
|
||||
<property name="logPath" value="logs/${app_name}" />
|
||||
<property name="log.max.file.size" value="100MB"/>
|
||||
<property name="log.max.history" value="60"/>
|
||||
<property name="log.total.size" value="3GB"/>
|
||||
|
||||
<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 name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) [%X{REQUEST_ID}] %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="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} [%X{REQUEST_ID}] ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
|
||||
|
||||
<!-- 日志输出的格式-->
|
||||
<!-- <property name="PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t-%L] %-5level %logger{36} %L %M - %msg%xEx%n"/>-->
|
||||
<contextName>logback</contextName>
|
||||
<!--输出到控制台 ConsoleAppender-->
|
||||
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<!--展示格式 layout-->
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<!--正常的info日志文件,输出到文件中-->
|
||||
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
|
||||
所以我们使用下面的策略,可以避免输出 Error 的日志,级别的其它高于DEBUG的-->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!--过滤 info-->
|
||||
<level>INFO</level>
|
||||
<!--匹配到就运行-->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!--没有匹配到就禁止-->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
|
||||
如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
|
||||
的日志改名为今天的日期。即,<File> 的日志都是当天的。-->
|
||||
<File>${logPath}/log_info.log</File>
|
||||
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,
|
||||
以防止日志填满整个磁盘空间-->
|
||||
<FileNamePattern>${logPath}/info/%d{yyyy-MM-dd}/log-info-%i.gz</FileNamePattern>
|
||||
<!--每个日志文件最大100MB,超过就重新生成-->
|
||||
<maxFileSize>${log.max.file.size}</maxFileSize>
|
||||
<!--只保留最近60天的日志-->
|
||||
<maxHistory>${log.max.history}</maxHistory>
|
||||
<!--日志整体最大
|
||||
可选的totalSizeCap属性控制所有归档文件的总大小。当超过总大小上限时,将异步删除最旧的存档。
|
||||
totalSizeCap属性也需要设置maxHistory属性。此外,“最大历史”限制总是首先应用,“总大小上限”限制其次应用。
|
||||
-->
|
||||
<totalSizeCap>${log.total.size}</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<!--日志输出编码格式化-->
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!--正常的warn日志文件,输出到文件中-->
|
||||
<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
|
||||
所以我们使用下面的策略,可以避免输出 Error 的日志,级别的其它高于DEBUG的-->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!--过滤 warn-->
|
||||
<level>WARN</level>
|
||||
<!--匹配到就运行-->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!--没有匹配到就禁止-->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<File>${logPath}/log_warn.log</File>
|
||||
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,
|
||||
以防止日志填满整个磁盘空间-->
|
||||
<FileNamePattern>${logPath}/warn/%d{yyyy-MM-dd}/log-warn-%i.gz</FileNamePattern>
|
||||
<!--每个日志文件最大100MB,超过就重新生成-->
|
||||
<maxFileSize>${log.max.file.size}</maxFileSize>
|
||||
<!--只保留最近60天的日志-->
|
||||
<maxHistory>${log.max.history}</maxHistory>
|
||||
<!--日志整体最大
|
||||
可选的totalSizeCap属性控制所有归档文件的总大小。当超过总大小上限时,将异步删除最旧的存档。
|
||||
totalSizeCap属性也需要设置maxHistory属性。此外,“最大历史”限制总是首先应用,“总大小上限”限制其次应用。
|
||||
-->
|
||||
<totalSizeCap>${log.total.size}</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<!--日志输出编码格式化-->
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<!--正常的error日志文件,输出到文件中-->
|
||||
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高,
|
||||
所以我们使用下面的策略,可以避免输出 Error 的日志,级别的其它高于DEBUG的-->
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!--过滤 error-->
|
||||
<level>ERROR</level>
|
||||
<!--匹配到就运行-->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!--没有匹配到就禁止-->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<File>${logPath}/log_error.log</File>
|
||||
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
|
||||
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,
|
||||
以防止日志填满整个磁盘空间-->
|
||||
<FileNamePattern>${logPath}/error/%d{yyyy-MM-dd}/log-error-%i.gz</FileNamePattern>
|
||||
<!--每个日志文件最大100MB,超过就重新生成-->
|
||||
<maxFileSize>${log.max.file.size}</maxFileSize>
|
||||
<!--只保留最近60天的日志-->
|
||||
<maxHistory>${log.max.history}</maxHistory>
|
||||
<!--日志整体最大
|
||||
可选的totalSizeCap属性控制所有归档文件的总大小。当超过总大小上限时,将异步删除最旧的存档。
|
||||
totalSizeCap属性也需要设置maxHistory属性。此外,“最大历史”限制总是首先应用,“总大小上限”限制其次应用。
|
||||
-->
|
||||
<totalSizeCap>${log.total.size}</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<!--日志输出编码格式化-->
|
||||
<encoder>
|
||||
<charset>UTF-8</charset>
|
||||
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<!--开启异步日志记录 异步输出,异步的log片段必须在同步段后面,否则不起作用 -->
|
||||
<appender name="INFO_FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<!-- 不丢失日志.默认的:如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志,
|
||||
当队列少于discardingThreshold设置的数量就会丢失 <= info 的日志 -->
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
|
||||
<queueSize>1024</queueSize>
|
||||
<!-- 不设置neverBolck的话调用的是put方法是阻塞的,设置为true后调用offer方法是不阻塞的-->
|
||||
<neverBlock>true</neverBlock>
|
||||
<appender-ref ref="INFO_FILE"/>
|
||||
</appender>
|
||||
|
||||
<!--开启异步日志记录 异步输出,异步的log片段必须在同步段后面,否则不起作用 -->
|
||||
<appender name="WARN_FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<queueSize>1024</queueSize>
|
||||
<neverBlock>true</neverBlock>
|
||||
<appender-ref ref="WARN_FILE"/>
|
||||
</appender>
|
||||
|
||||
<!--开启异步日志记录 异步输出,异步的log片段必须在同步段后面,否则不起作用 -->
|
||||
<appender name="ERROR_FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<discardingThreshold>0</discardingThreshold>
|
||||
<queueSize>1024</queueSize>
|
||||
<neverBlock>true</neverBlock>
|
||||
<appender-ref ref="ERROR_FILE"/>
|
||||
</appender>
|
||||
|
||||
<!-- 我之前就遇到过很多关于 AsyncAppender 异步日志的坑,这些坑可以归结为三类:
|
||||
记录异步日志撑爆内存;
|
||||
记录异步日志出现日志丢失;
|
||||
记录异步日志出现阻塞。
|
||||
出现这个问题的原因在于,AsyncAppender 提供了一些配置参数,而我们没用对。我们结合相关源码分析一下:
|
||||
includeCallerData 用于控制是否收集调用方数据,默认是 false,此时方法行号、方法名等信息将不能显示(源码第 2 行以及 7 到 11 行)。
|
||||
queueSize 用于控制阻塞队列大小,使用的 ArrayBlockingQueue 阻塞队列(源码第 15 到 17 行),默认大小是 256,即内存中最多保存 256 条日志。
|
||||
discardingThreshold 是控制丢弃日志的阈值,主要是防止队列满后阻塞。默认情况下,队列剩余量低于队列长度的 20%,就会丢弃 TRACE、DEBUG 和 INFO 级别的日志。(参见源码第 3 到 6 行、18 到 19 行、26 到 27 行、33 到 34 行、40 到 42 行)
|
||||
neverBlock 用于控制队列满的时候,加入的数据是否直接丢弃,不会阻塞等待,默认是 false(源码第 44 到 68 行)。这里需要注意一下 offer 方法和 put 方法的区别,当队列满的时候 offer 方法不阻塞,而 put 方法会阻塞;neverBlock 为 true 时,使用 offer 方法。
|
||||
|
||||
我们可以继续分析下异步记录日志出现坑的原因。
|
||||
queueSize 设置得特别大,就可能会导致 OOM。
|
||||
queueSize 设置得比较小(默认值就非常小),且 discardingThreshold 设置为大于 0 的值(或者为默认值),队列剩余容量少于 discardingThreshold 的配置就会丢弃 <=INFO 的日志。这里的坑点有两个。一是,因为 discardingThreshold 的存在,设置 queueSize 时容易踩坑。比如,本例中最大日志并发是 1000,即便设置 queueSize 为 1000 同样会导致日志丢失。二是,[discardingThreshold 参数容易有歧义,它不是百分比,而是日志条数]。对于总容量 10000 的队列,如果希望队列剩余容量少于 1000 条的时候丢弃,需要配置为 1000。
|
||||
neverBlock 默认为 false,意味着总可能会出现阻塞。如果 discardingThreshold 为 0,那么队列满时再有日志写入就会阻塞;如果 discardingThreshold 不为 0,也只会丢弃 <=INFO 级别的日志,那么出现大量错误日志时,还是会阻塞程序。
|
||||
可以看出 queueSize、discardingThreshold 和 neverBlock 这三个参数息息相关,务必按需进行设置和取舍,到底是性能为先,还是数据不丢为先:
|
||||
|
||||
如果考虑绝对性能为先,那就设置 neverBlock 为 true,永不阻塞。
|
||||
如果考虑绝对不丢数据为先,那就设置 discardingThreshold 为 0,即使是 <=INFO 的级别日志也不会丢,但最好把 queueSize 设置大一点,毕竟默认的 queueSize 显然太小,太容易阻塞。
|
||||
如果希望兼顾两者,可以丢弃不重要的日志,把 queueSize 设置大一点,再设置一个合理的 discardingThreshold。
|
||||
-->
|
||||
|
||||
<!--指定最基础的日志输出级别 INFO DEBUG-->
|
||||
<root level="INFO">
|
||||
<!--appender将会添加到这个loger-->
|
||||
<appender-ref ref="consoleLog"/>
|
||||
<appender-ref ref="INFO_FILE_ASYNC"/>
|
||||
<appender-ref ref="WARN_FILE_ASYNC"/>
|
||||
<appender-ref ref="ERROR_FILE_ASYNC"/>
|
||||
</root>
|
||||
|
||||
<!-- 定义指定package的日志级别 logger 标签中 .* 无效-->
|
||||
<!-- <logger name="org.springframework" level="DEBUG"/>-->
|
||||
<!-- <logger name="org.mybatis" level="DEBUG"/>-->
|
||||
<!-- <logger name="java.sql.Connection" level="DEBUG"/>-->
|
||||
<!-- <logger name="java.sql.Statement" level="DEBUG"/>-->
|
||||
<!-- <logger name="java.sql.PreparedStatement" level="DEBUG"/>-->
|
||||
<!-- <logger name="io.lettuce.*" level="INFO"/>-->
|
||||
<!-- <logger name="io.netty.*" level="ERROR"/>-->
|
||||
<!-- <logger name="com.rabbitmq.*" level="DEBUG"/>-->
|
||||
<!-- <logger name="org.springframework.amqp.*" level="DEBUG"/>-->
|
||||
<!-- <logger name="org.springframework.scheduling.*" level="DEBUG"/>-->
|
||||
<!-- <logger name="org.springframework.scheduling.*" level="DEBUG"/>-->
|
||||
|
||||
|
||||
<!-- 4 最终的策略:
|
||||
基本策略(root级) + 根据profile在启动时, logger标签中定制化package日志级别(优先级高于上面的root级)-->
|
||||
<!-- <springProfile name="dev">-->
|
||||
<!-- <root level="info">-->
|
||||
<!-- <appender-ref ref="CONSOLE" />-->
|
||||
<!-- <appender-ref ref="DEBUG_FILE" />-->
|
||||
<!-- <appender-ref ref="INFO_FILE" />-->
|
||||
<!-- <appender-ref ref="WARN_FILE" />-->
|
||||
<!-- <appender-ref ref="ERROR_FILE" />-->
|
||||
<!-- <appender-ref ref="ALL_FILE" />-->
|
||||
<!-- </root>-->
|
||||
<!-- <logger name="com.xusanduo.demo" level="debug"/> <!– 开发环境, 指定某包日志为debug级 –>-->
|
||||
<!-- </springProfile>-->
|
||||
|
||||
<!--定义com.xxx..xx..xx包下的日志信息不上传,直接输出到fileDEBUGLog和fileErrorLog这个两个appender中,日志级别为DEBUG-->
|
||||
<!-- <logger name="com.xxx.xxx.xx" additivity="false" level="DEBUG">-->
|
||||
<!-- <appender-ref ref="fileDEBUGLog"/>-->
|
||||
<!-- <appender-ref ref="fileErrorLog"/>-->
|
||||
<!-- </logger>-->
|
||||
|
||||
<!--
|
||||
<logger>用来设置某一个包或者具体的某一个类的日志打印级别、
|
||||
以及指定<appender>。<logger>仅有一个name属性,
|
||||
一个可选的level和一个可选的addtivity属性。
|
||||
name:用来指定受此logger约束的某一个包或者具体的某一个类。
|
||||
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
|
||||
还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。
|
||||
如果未设置此属性,那么当前logger将会继承上级的级别。
|
||||
addtivity:是否向上级logger传递打印信息。默认是true。
|
||||
<logger name="org.springframework.web" level="info"/>
|
||||
<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
|
||||
-->
|
||||
|
||||
<!--
|
||||
使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
|
||||
第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
|
||||
第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
|
||||
【logging.level.org.mybatis=debug logging.level.dao=debug】
|
||||
<logger name="xxxx.xx.dao" level="DEBUG"/>
|
||||
指定到mapper.xml对应的dao所在的包。
|
||||
-->
|
||||
|
||||
<!--
|
||||
root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
|
||||
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
|
||||
不能设置为INHERITED或者同义词NULL。默认是DEBUG
|
||||
可以包含零个或多个元素,标识这个appender将会添加到这个logger。
|
||||
-->
|
||||
|
||||
</configuration>
|
Loading…
Reference in New Issue
Block a user