移除logback配置文件,直接在yml文件里配置参数

This commit is contained in:
谷成伟 2024-06-20 14:36:04 +08:00
parent 3b6959d678
commit 42465589cf
2 changed files with 0 additions and 547 deletions

View File

@ -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"/> &lt;!&ndash; 开发环境, 指定某包日志为debug级 &ndash;&gt;-->
<!-- </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>

View File

@ -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"/> &lt;!&ndash; 开发环境, 指定某包日志为debug级 &ndash;&gt;-->
<!-- </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>