kindergarten_java/lesingle-edu-reading-platform-backend/src/main/resources/logback-spring.xml
En 79d98be366 feat(后端): 添加日志链路追踪功能,支持生产环境快速错误定位
- 新增 TraceIdFilter 过滤器,为每个请求生成唯一链路追踪 ID
- 修改 logback-spring.xml,所有日志输出包含 traceId
- 修改 RequestLogAspect,记录用户上下文信息(userId, role)
- 修改 GlobalExceptionHandler,异常日志包含用户信息和请求 URI
- 修改 application-test.yml,添加 SQL 日志全量输出配置
- 修改 JwtAuthenticationFilter,添加 Order 注解确保过滤器顺序
- 新增文档:日志优化方案 - 生产环境错误定位.md

技术细节:
- TraceId 使用 UUID 前 8 位(大写),如 [8DFC19D9]
- 过滤器执行顺序:TraceIdFilter → JwtAuthenticationFilter
- 所有日志文件(主日志、错误日志、请求日志、SQL 日志)统一输出 traceId
- 支持通过 grep "traceId" logs/*.log 快速定位请求完整链路

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 14:40:16 +08:00

185 lines
7.8 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<!-- ==================== 变量定义 ==================== -->
<!-- 日志保留天数 -->
<property name="LOG_MAX_HISTORY" value="30"/>
<!-- 单个日志文件最大大小 -->
<property name="LOG_MAX_FILE_SIZE" value="100MB"/>
<!-- 总日志大小上限 -->
<property name="LOG_TOTAL_CAP" value="2GB"/>
<!-- 日志存储目录 -->
<property name="LOG_HOME" value="logs"/>
<!-- 应用名称 -->
<property name="APP_NAME" value="reading-platform"/>
<!-- ==================== 控制台输出 ==================== -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId}] %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- ==================== 文件滚动输出 - 主日志 ==================== -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 日志文件名格式:按天滚动 -->
<fileNamePattern>${LOG_HOME}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 保留 30 天日志 -->
<maxHistory>${LOG_MAX_HISTORY}</maxHistory>
<!-- 按大小滚动(单个文件最大 100MB -->
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${LOG_MAX_FILE_SIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<!-- 总日志大小上限 2GB -->
<totalSizeCap>${LOG_TOTAL_CAP}</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId}] %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- ==================== 错误日志单独输出 ==================== -->
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}-error.log</file>
<!-- 只记录 ERROR 级别日志 -->
<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.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}-error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>${LOG_MAX_HISTORY}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${LOG_MAX_FILE_SIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<totalSizeCap>500MB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId}] %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- ==================== 请求日志单独输出 ==================== -->
<appender name="REQUEST_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}-request.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}-request.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>${LOG_MAX_HISTORY}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${LOG_MAX_FILE_SIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<totalSizeCap>500MB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId}] %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- ==================== SQL 日志 - 只记录慢 SQL 和错误 SQL ==================== -->
<appender name="SQL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${APP_NAME}-sql.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${APP_NAME}-sql.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxHistory>${LOG_MAX_HISTORY}</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>${LOG_MAX_FILE_SIZE}</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<totalSizeCap>300MB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId}] %logger{36} - %msg%n</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- ==================== 开发环境配置 ==================== -->
<springProfile name="dev">
<!-- 根日志级别 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
<!-- 业务日志输出 DEBUG 级别 -->
<logger name="com.lesingle.edu" level="DEBUG"/>
<!-- 请求日志(单独输出到 request.log -->
<logger name="com.lesingle.edu.common.aspect.RequestLogAspect" level="INFO" additivity="false">
<appender-ref ref="REQUEST_FILE"/>
</logger>
<!-- MyBatis SQL 日志(开发环境全量记录) -->
<logger name="com.baomidou.mybatisplus" level="DEBUG"/>
<logger name="com.lesingle.edu.mapper" level="DEBUG"/>
</springProfile>
<!-- ==================== 测试环境配置 ==================== -->
<springProfile name="test">
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
<!-- 请求日志 -->
<logger name="com.lesingle.edu.common.aspect.RequestLogAspect" level="INFO" additivity="false">
<appender-ref ref="REQUEST_FILE"/>
</logger>
<!-- 业务日志 -->
<logger name="com.lesingle.edu" level="INFO"/>
<!-- MyBatis SQL 日志(只记录 DEBUG 及以上) -->
<logger name="com.baomidou.mybatisplus" level="INFO"/>
<logger name="com.lesingle.edu.mapper" level="INFO"/>
</springProfile>
<!-- ==================== 生产环境配置 ==================== -->
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
<!-- 业务日志 INFO 级别 -->
<logger name="com.lesingle.edu" level="INFO"/>
<!-- 请求日志(单独输出到 request.log -->
<logger name="com.lesingle.edu.common.aspect.RequestLogAspect" level="INFO" additivity="false">
<appender-ref ref="REQUEST_FILE"/>
</logger>
<!-- MyBatis SQL 日志(生产环境只记录 WARN 和 ERROR即慢 SQL 和错误 SQL -->
<logger name="com.baomidou.mybatisplus" level="WARN" additivity="false">
<appender-ref ref="SQL_FILE"/>
</logger>
<logger name="com.lesingle.edu.mapper" level="WARN" additivity="false">
<appender-ref ref="SQL_FILE"/>
</logger>
<!-- Spring 框架日志 -->
<logger name="org.springframework" level="WARN"/>
<logger name="org.hibernate" level="WARN"/>
</springProfile>
</configuration>