@ -1,25 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration >
<!-- 从 环境变量读取配置 -->
<springProperty scope= "context" name= "APP_NAME" source= " spring.application.name " defaultValue= "worklog-api" />
<springProperty scope= "context" name= "LOG_PATH" source= " logging.file.path " defaultValue= "./logs" />
<springProperty scope= "context" name= "LOG_LEVEL_ROOT" source= " logging.level.root " defaultValue= "INFO" />
<springProperty scope= "context" name= "LOG_LEVEL_APP" source= " logging.level.app " defaultValue= "DEBUG" />
<!-- 从 env.properties 读取配置(生产环境由 start.sh 注入为系统属性,开发环境通过 spring.config.import 加载) -->
<springProperty scope= "context" name= "APP_NAME" source= " APP_NAME " defaultValue= "worklog-api" />
<springProperty scope= "context" name= "LOG_PATH" source= " LOG_PATH " defaultValue= "./logs" />
<springProperty scope= "context" name= "LOG_LEVEL_ROOT" source= " LOG_LEVEL_ROOT " defaultValue= "INFO" />
<springProperty scope= "context" name= "LOG_LEVEL_APP" source= " LOG_LEVEL_APP " defaultValue= "DEBUG" />
<!-- 日志格式: 强制 包含 traceId 和 spanId -->
<!-- 日志格式: 包含 traceId 和 spanId -->
<property name= "LOG_PATTERN" value= "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId:-}][%X{spanId:-}] %-5level %logger{50} - %msg%n" />
<!-- 控制台输出 -->
<appender name= "CONSOLE" class= "ch.qos.logback.core.ConsoleAppender" >
<!-- ===== Appenders ===== -->
<!-- 1. AOP日志: ApiLogAspect 请求/响应日志( 不含ERROR, ERROR只输出到error.log) -->
<appender name= "AOP_FILE" class= "ch.qos.logback.core.rolling.RollingFileAppender" >
<file > ${LOG_PATH}/aop.log</file>
<filter class= "ch.qos.logback.classic.filter.ThresholdFilter" >
<level > DEBUG</level>
</filter>
<filter class= "ch.qos.logback.classic.filter.LevelFilter" >
<level > ERROR</level>
<onMatch > DENY</onMatch>
<onMismatch > NEUTRAL</onMismatch>
</filter>
<encoder >
<pattern > ${LOG_PATTERN}</pattern>
<charset > UTF-8</charset>
</encoder>
<rollingPolicy class= "ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy" >
<fileNamePattern > ${LOG_PATH}/aop-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize > 100MB</maxFileSize>
<maxHistory > 30</maxHistory>
</rollingPolicy>
</appender>
<!-- 应用日志文件输出 - 直接输出到 logs/ 目录 -->
<appender name= "FILE" class= "ch.qos.logback.core.rolling.RollingFileAppender" >
<!-- 2. 应用日志: com.wjbl.worklog 业务日志( 不含ERROR, ERROR只输出到error.log) -->
<appender name= " APP_ FILE" class= "ch.qos.logback.core.rolling.RollingFileAppender" >
<file > ${LOG_PATH}/app.log</file>
<filter class= "ch.qos.logback.classic.filter.ThresholdFilter" >
<level > DEBUG</level>
</filter>
<filter class= "ch.qos.logback.classic.filter.LevelFilter" >
<level > ERROR</level>
<onMatch > DENY</onMatch>
<onMismatch > NEUTRAL</onMismatch>
</filter>
<encoder >
<pattern > ${LOG_PATTERN}</pattern>
<charset > UTF-8</charset>
@ -31,9 +55,17 @@
</rollingPolicy>
</appender>
<!-- SQL日志文件输出 - MyBatis - Plus SQL 日志独立输出 -->
<!-- 3. SQL日志: 数据库操作日志( 不含ERROR, ERROR只输出到error.log) -->
<appender name= "SQL_FILE" class= "ch.qos.logback.core.rolling.RollingFileAppender" >
<file > ${LOG_PATH}/sql.log</file>
<filter class= "ch.qos.logback.classic.filter.ThresholdFilter" >
<level > DEBUG</level>
</filter>
<filter class= "ch.qos.logback.classic.filter.LevelFilter" >
<level > ERROR</level>
<onMatch > DENY</onMatch>
<onMismatch > NEUTRAL</onMismatch>
</filter>
<encoder >
<pattern > ${LOG_PATTERN}</pattern>
<charset > UTF-8</charset>
@ -45,21 +77,68 @@
</rollingPolicy>
</appender>
<!-- MyBatis - Plus SQL日志 -->
<!-- 4. 异常日志:所有 ERROR 级别日志集中输出 -->
<appender name= "ERROR_FILE" class= "ch.qos.logback.core.rolling.RollingFileAppender" >
<file > ${LOG_PATH}/error.log</file>
<filter class= "ch.qos.logback.classic.filter.ThresholdFilter" >
<level > ERROR</level>
</filter>
<encoder >
<pattern > ${LOG_PATTERN}</pattern>
<charset > UTF-8</charset>
</encoder>
<rollingPolicy class= "ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy" >
<fileNamePattern > ${LOG_PATH}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize > 100MB</maxFileSize>
<maxHistory > 30</maxHistory>
</rollingPolicy>
</appender>
<!-- 控制台输出( 开发环境调试用, 不含ERROR, ERROR只输出到error.log) -->
<appender name= "CONSOLE" class= "ch.qos.logback.core.ConsoleAppender" >
<filter class= "ch.qos.logback.classic.filter.ThresholdFilter" >
<level > DEBUG</level>
</filter>
<filter class= "ch.qos.logback.classic.filter.LevelFilter" >
<level > ERROR</level>
<onMatch > DENY</onMatch>
<onMismatch > NEUTRAL</onMismatch>
</filter>
<encoder >
<pattern > ${LOG_PATTERN}</pattern>
<charset > UTF-8</charset>
</encoder>
</appender>
<!-- ===== Loggers ===== -->
<!-- ApiLogAspect → aop.log( 比 com.wjbl.worklog 更具体,优先匹配) -->
<logger name= "com.wjbl.worklog.config.ApiLogAspect" level= "DEBUG" additivity= "false" >
<appender-ref ref= "AOP_FILE" />
<appender-ref ref= "ERROR_FILE" />
</logger>
<!-- MyBatis Mapper SQL → sql.log -->
<logger name= "com.wjbl.worklog.data.mapper" level= "DEBUG" additivity= "false" >
<appender-ref ref= "SQL_FILE" />
<appender-ref ref= "CONSOLE" />
<appender-ref ref= " ERROR_FI LE"/>
</logger>
<!-- MyBatis - Plus 框架日志 -->
<!-- MyBatis - Plus 框架 SQL → sql.log -->
<logger name= "com.baomidou.mybatisplus" level= "DEBUG" additivity= "false" >
<appender-ref ref= "SQL_FILE" />
<appender-ref ref= "CONSOLE" />
<appender-ref ref= " ERROR_FI LE"/>
</logger>
<!-- 根日志级别 -->
<!-- com.wjbl.worklog 业务日志 → app.log( ApiLogAspect 和 mapper 已被上方更具体的 logger 拦截) -->
<logger name= "com.wjbl.worklog" level= "${LOG_LEVEL_APP}" additivity= "false" >
<appender-ref ref= "APP_FILE" />
<appender-ref ref= "ERROR_FILE" />
</logger>
<!-- 根日志:其余所有日志 → stdout.log -->
<root level= "${LOG_LEVEL_ROOT}" >
<appender-ref ref= "ERROR_FILE" />
<appender-ref ref= "CONSOLE" />
<appender-ref ref= "FILE" />
</root>
</configuration>