SpringBoot项目logback-spring.xml日志管理配置
一、为什么需要专门配置 logback-spring.xml?
1、与默认配置的区别
- Spring Boot 默认日志配置:Spring Boot 内置了 Logback 的默认配置,开箱即用;
- logback-spring.xml 的优势:专门为 Spring Boot 设计的配置文件,支持 Spring 特有的功能扩展;
- 命名约定:使用
logback-spring.xml而非logback.xml可以让 Spring Boot 完全控制日志初始化过程。
2、解决的核心问题
- 实现多环境(dev/test/prod)差异化的日志配置;
- 支持 Spring Profile 条件化配置;
- 在日志配置中使用 Spring 属性占位符。
二、配置 logback-spring.xml 的主要优点?
1、Spring Profile 支持(最重要优势)
<!-- 开发环境:控制台输出,级别为DEBUG -->
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
<!-- 生产环境:文件输出,级别为INFO -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
</springProfile>
2、多环境适配
- 不同环境使用不同的日志策略:
- 开发环境:侧重可读性,控制台彩色输出;
- 生产环境:侧重性能和分析,文件输出+日志切割;
- 测试环境:可配置为收集特定包/类的详细日志。
3、性能优化
<!-- 异步日志提升性能 -->
<appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE"/>
<queueSize>512</queueSize>
<discardingThreshold>0</discardingThreshold>
</appender>
4、精细化日志控制
<!-- 针对不同包设置不同日志级别 -->
<logger name="com.example.service" level="DEBUG"/>
<logger name="org.hibernate" level="WARN"/>
<logger name="org.apache.kafka" level="INFO"/>
5、Spring 属性注入
<!-- 使用Spring属性 -->
<property resource="application.properties"/>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${LOG_PATH:-./logs}/application.log</file>
...
</appender>
6、结构化日志管理
-
按级别分离日志(INFO/ERROR分开存储),方便快速排查、定位错误信息;
-
按时间/大小滚动分割归档、自动压缩(可节省60~80磁盘空间);
-
自动清理历史日志文件。
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/application.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<maxHistory>30</maxHistory> <!-- 保留30天 -->
</rollingPolicy>
</appender>
7、增强的可读性
-
支持彩色控制台输出;
-
自定义日志格式模板;
-
包含有用的上下文信息(traceId、用户ID等)。
8、监控与诊断优化
-
集成 MDC(Mapped Diagnostic Context)用于链路追踪;
-
支持 JSON 格式输出,便于日志采集分析;
-
可配置敏感信息脱敏。
三、使用注意事项
1、文件存放位置
- 通常放在
src/main/resources/目录下
2、加载顺序
- Spring Boot 会优先加载
logback-spring.xml
3、热加载
- 配置
scan="true"支持修改后自动重载(生产环境建议关闭)
4、向后兼容
- 也支持标准的 logback.xml,但会失去 Spring 集成特性
四、生产配置推荐示例(可直接复制使用,局部需按需调整)
<?xml version="1.0" encoding="UTF-8"?>
<!--scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。(生产建议关闭,基本不会在生产上改动)-->
<!--scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟(生产建议长一些,避免太频繁的性能消耗)。-->
<!--debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。-->
<configuration scan="false" scanPeriod="5 minutes" debug="false">
<!-- 定义日志文件的存储地址和文件名称,简单说就是定义变量,后面可以使用${xx}来使用变量 -->
<!--info日志文件存储层级-->
<property name="INFO_LOG_FILE_LEVEL" value="logs/info"/>
<!--error日志文件存储层级-->
<property name="ERROR_LOG_FILE_LEVEL" value="logs/error"/>
<!--info日志文件名称-->
<property name="INFO_LOG_FILE_NAME" value="info"/>
<!--error日志文件名称-->
<property name="ERROR_LOG_FILE_NAME" value="error"/>
<!-- appender是configuration的子节点,是负责写日志的组件 -->
<!-- ConsoleAppender:把日志输出到控制台 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- 默认情况下,每个日志事件都会立即刷新到基础输出流。这种默认方法更安全,因为如果应用程序在没有正确关闭appender的情况下退出,则日志事件不会丢失 -->
<!-- 但为了显着增加日志记录吞吐量,可以将immediateFlush属性设置为false -->
<immediateFlush>true</immediateFlush>
<encoder>
<!--[TRACEID:%X{traceId}]:用于日志线程跟踪,结合MDC(映射诊断上下文)工具-->
<!-- %37():如果字符没有37个字符长度,则左侧用空格补齐 -->
<!-- %-37():如果字符没有37个字符长度,则右侧用空格补齐 -->
<!-- %15.15():如果记录的线程字符长度小于15(第一个)则用空格在左侧补齐,如果字符长度大于15(第二个),则从开头开始截断多余的字符 -->
<!-- %msg:日志打印详情 -->
<!--%cyan():颜色转换词,用于在控制台中区分不同的日志部分-->
<!--:%line:前面的:为分隔符,%line表示会输出日志代码所在的行号-->
<!-- %-40.40():-表示左对齐(默认是右对齐)如果记录的logger字符长度小于40(第一个)则用空格在右侧补齐,如果字符长度大于40(第二个),则从开头开始截断多余的字符 -->
<!-- %n:换行符 -->
<!-- %highlight():转换说明符以粗体红色显示其级别为ERROR的事件,红色为WARN,BLUE为INFO,以及其他级别的默认颜色 -->
<pattern>[TRACEID:%X{traceId}] %d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level)-[%15.15(%thread)] %cyan(%-40.40(%logger{40}):%line): %msg%n</pattern>
<!-- 控制台也要使用UTF-8,不要使用GBK,否则会中文乱码 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- info 日志收集-->
<!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件,
以下的大概意思是:
1.先按日期存日志,日期变了,将前一天的日志文件名重命名为XXX%日期%索引,新的日志仍然是${INFO_LOG_FILE_NAME}.log
2.如果日期没有发生变化,但是当前日志的文件大小超过100MB时,对当前日志进行分割、重命名、压缩
-->
<appender name="INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件路径和名称-->
<File>${INFO_LOG_FILE_LEVEL}/${INFO_LOG_FILE_NAME}.log</File>
<!--是否追加到文件末尾,默认为true-->
<append>true</append>
<!--日志级别收集匹配规则-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<!-- 如果命中ERROR就禁止这条日志 -->
<onMatch>DENY</onMatch>
<!-- 如果没有命中就接收 -->
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--有两个与RollingFileAppender: 交互的重要子组件:
RollingPolicy: 负责执行翻转所需的操作。
TriggeringPolicy: 将确定是否以及何时发生翻转。因此RollingPolicy负责什么和TriggeringPolicy负责什么时候
RollingFileAppender必须同时设置RollingPolicy和TriggeringPolicy;但如果其RollingPolicy也实现了TriggeringPolicy接口,则只需要显式指定前者-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
<!-- 文件名:${INFO_LOG_FILE_LEVEL}/${INFO_LOG_FILE_NAME}-2024-02-01-0.log.gz -->
<!-- 注意:SizeAndTimeBasedRollingPolicy中 %i和%d令牌都是强制性的,必须存在要不会报错 -->
<fileNamePattern>${INFO_LOG_FILE_LEVEL}/${INFO_LOG_FILE_NAME}-%d{yyyy-MM-dd}-%i.log.gz</fileNamePattern>
<!-- 每产生一个日志文件,该日志文件的保存期限为180天, maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的.
例如上面选用了yyyy-MM-dd,则单位为天
如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd-->
<maxHistory>180</maxHistory>
<!-- 每个日志文件到10mb的时候开始切分,最多保留180天,但最大到20GB,哪怕没到180天也要删除多余的日志 -->
<totalSizeCap>20GB</totalSizeCap>
<!-- 应用启动时立即清理过期日志文件 -->
<cleanHistoryOnStart>true</cleanHistoryOnStart>
<!-- maxFileSize:文件分片大小,100MB,不宜太小,避免频繁分片消耗 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<!--编码器-->
<encoder>
<!--指定日志输出格式-->
<pattern>[TRACEID:%X{traceId}] %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level-[%15.15(%thread)] %-40.40(%logger{40}:%line): %msg%n</pattern>
<!--设置字符集,防止中文乱码-->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 异步INFO日志收集器:包装INFO_LOG,实现异步写入,提升性能 -->
<appender name="ASYNC_INFO" class="ch.qos.logback.classic.AsyncAppender">
<!-- 队列大小,默认256,设置为512以应对突发流量 -->
<queueSize>512</queueSize>
<!-- 丢弃阈值,0表示不丢弃,队列满时阻塞 -->
<discardingThreshold>0</discardingThreshold>
<!-- 是否永不阻塞,false表示队列满时阻塞业务线程,确保日志不丢失 -->
<neverBlock>false</neverBlock>
<!-- 包装实际的INFO_LOG appender -->
<appender-ref ref="INFO_LOG"/>
</appender>
<!-- error 日志收集-->
<appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--日志文件路径和名称-->
<File>${ERROR_LOG_FILE_LEVEL}/${ERROR_LOG_FILE_NAME}.log</File>
<!--是否追加到文件末尾,默认为true-->
<append>true</append>
<!-- ThresholdFilter过滤低于指定阈值的事件。对于等于或高于阈值的事件,ThresholdFilter将在调用其decision方法时响应NEUTRAL。但将拒绝级别低于阈值的事件 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- 低于ERROR级别的日志(debug,info)将被拒绝,等于或者高于ERROR的级别将接收 -->
<level>ERROR</level>
</filter>
<!--有两个与RollingFileAppender交互的重要子组件:
RollingPolicy: 负责执行翻转所需的操作。
TriggeringPolicy: 将确定是否以及何时发生翻转。因此RollingPolicy负责什么和TriggeringPolicy负责什么时候
RollingFileAppender必须同时设置RollingPolicy和TriggeringPolicy;但如果其RollingPolicy也实现了TriggeringPolicy接口,则只需要显式指定前者-->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- 日志文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 -->
<!-- 文件名:${ERROR_LOG_FILE_LEVEL}/${ERROR_LOG_FILE_NAME}.2024-02-01.0.log.gz -->
<!-- 注意:SizeAndTimeBasedRollingPolicy中 %i和%d令牌都是强制性的,必须存在要不会报错 -->
<fileNamePattern>${ERROR_LOG_FILE_LEVEL}/${ERROR_LOG_FILE_NAME}.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<!-- 每产生一个日志文件,该日志文件的保存期限为180天, maxHistory的单位是根据fileNamePattern中的翻转策略自动推算出来的.
例如上面选用了yyyy-MM-dd,则单位为天
如果上面选用了yyyy-MM,则单位为月,另外上面的单位默认为yyyy-MM-dd-->
<maxHistory>180</maxHistory>
<!-- 每个日志文件到10mb的时候开始切分,最多保留180天,但最大到20GB,哪怕没到180天也要删除多余的日志 -->
<totalSizeCap>20GB</totalSizeCap>
<!-- 应用启动时立即清理过期日志文件 -->
<cleanHistoryOnStart>true</cleanHistoryOnStart>
<!-- maxFileSize:文件分片大小,100MB,不宜太小,避免频繁分片消耗 -->
<maxFileSize>100MB</maxFileSize>
</rollingPolicy>
<!--编码器-->
<encoder>
<!--指定日志输出格式-->
<pattern>[TRACEID:%X{traceId}] %d{yyyy-MM-dd HH:mm:ss.SSS} %-5level-[%15.15(%thread)] %-40.40(%logger{40}:%line): %msg%n</pattern>
<!--设置字符集,防止中文乱码-->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- (root)根记录器 -->
<!-- 开发环境:控制台输出,级别为DEBUG -->
<springProfile name="dev">
<root level="DEBUG">
<!--控制台输出-->
<appender-ref ref="CONSOLE"/>
<!--INFO 日志同步写入-->
<appender-ref ref="INFO_LOG"/>
<!--ERROR 日志同步写入-->
<appender-ref ref="ERROR_LOG"/>
</root>
<!-- 开发环境:启用MyBatis SQL日志,便于调试 -->
<!-- 自己项目的包路径 -->
<logger name="com.cloud.mapper" level="DEBUG"/>
</springProfile>
<!-- 生产环境:文件输出,级别为INFO -->
<springProfile name="prod">
<root level="INFO">
<!--控制台输出-->
<appender-ref ref="CONSOLE"/>
<!--按需选择:INFO 日志同步写入,日志完整度要求较高、低流量应用等场景使用-->
<appender-ref ref="INFO_LOG"/>
<!--按需选择:INFO 日志异步写入(若需提升日志性能并允许日志存在记录延迟跟丢失风险,则可采用。虽然队列满时会阻塞确保不丢失,但应用可能不正常关闭导致日志丢失)-->
<!-- <appender-ref ref="ASYNC_INFO"/>-->
<!--ERROR 日志同步写入(确保关键错误日志不丢失)-->
<appender-ref ref="ERROR_LOG"/>
</root>
<!-- 生产环境:如需临时启用MyBatis SQL日志排查问题,取消下面注释并重启应用 -->
<!-- 自己项目的包路径 -->
<!-- <logger name="com.cloud.mapper" level="TRACE"/> -->
</springProfile>
<!-- 其他框架日志配置(按需启用) -->
<!-- <logger name="org.springframework" level="DEBUG"/> --> <!-- Spring框架DEBUG日志 -->
<!-- <logger name="org.mybatis" level="DEBUG"/> --> <!-- MyBatis框架DEBUG日志 -->
<!-- <logger name="io.lettuce.*" level="INFO"/> --> <!-- Redis客户端 -->
<!-- <logger name="io.netty.*" level="ERROR"/> --> <!-- Netty网络通信 -->
<!-- <logger name="com.rabbitmq.*" level="DEBUG"/> --> <!-- RabbitMQ -->
</configuration>

浙公网安备 33010602011771号