Java Log4j2
·
Log4j2 使用规则文档
一、框架概述
1.1 什么是 Log4j2
Apache Log4j2 是 Log4j 的升级版本,是一个功能强大的日志框架,提供了:
- 高性能: 异步日志记录,性能比 Log4j 1.x 和 Logback 更好
- 灵活配置: 支持 XML、JSON、YAML、Properties 等多种配置格式
- 插件化架构: 支持自定义 Appender、Filter、Layout 等组件
- 自动重载配置: 支持配置文件热更新(无需重启应用)
- 多种输出方式: 支持控制台、文件、数据库、JMS、Socket 等多种输出目标
1.2 技术栈
- Log4j2 版本: 2.20.0
- Spring Boot: 2.7.18
- Spring Boot Log4j2 Starter: 自动配置 Log4j2
- Lombok: 可选使用
@Slf4j注解(但项目中使用原生 Log4j2 API)
1.3 为什么选择 Log4j2
- 性能优势: 异步日志性能比 Logback 提升 10-20 倍
- 功能强大: 支持更丰富的过滤器和布局器
- 配置灵活: 支持多种配置格式和动态配置
- 社区活跃: Apache 基金会维护,更新及时
- 安全性: 修复了 Log4j 1.x 的安全漏洞
二、依赖配置
2.1 Maven 依赖
在 pom.xml 中配置:
<properties>
<log4j2.version>2.20.0</log4j2.version>
</properties>
<dependencies>
<!-- Spring Boot Starter Web (排除 logback,使用 log4j2) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
<exclusions>
<!-- 排除 Spring Boot 默认的 logback -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring Boot Log4j2 Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Starter Test (也需要排除 logback) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 如果使用第三方库(如 MyBatis 中间件),也需要排除其 logback 依赖 -->
<dependency>
<groupId>ins.framework</groupId>
<artifactId>ins-framework-mybatis</artifactId>
<version>6.2.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
2.2 依赖说明
关键点:
- ✅ 必须排除
spring-boot-starter-logging(包含 logback) - ✅ 必须添加
spring-boot-starter-log4j2 - ✅ 第三方依赖中的 logback 也需要排除
- ✅ Spring Boot 会自动管理 Log4j2 的版本
三、配置文件详解
3.1 配置文件位置
配置文件: src/main/resources/log4j2.xml
Spring Boot 会自动识别以下位置的配置文件(按优先级):
log4j2-spring.xml(推荐,支持 Spring Profile)log4j2.xmllog4j2.propertieslog4j2.jsonlog4j2.yaml
3.2 配置文件结构
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<!-- 1. Properties: 定义变量 -->
<Properties>
<Property name="LOG_HOME">logs</Property>
<Property name="LOG_FILE_NAME">monitor</Property>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
<!-- 2. Appenders: 定义日志输出目标 -->
<Appenders>
<!-- 控制台输出 -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}"/>
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
<!-- 文件输出 -->
<RollingFile name="FileAppender" fileName="${LOG_HOME}/${LOG_FILE_NAME}.log"
filePattern="${LOG_HOME}/${LOG_FILE_NAME}-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</Appenders>
<!-- 3. Loggers: 定义日志记录器 -->
<Loggers>
<Logger name="pdfc.monitor" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
</Logger>
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
</Root>
</Loggers>
</Configuration>
3.3 配置属性说明
3.3.1 Configuration 属性
| 属性 | 说明 | 示例 |
|---|---|---|
status |
Log4j2 内部日志级别 | WARN、DEBUG、ERROR |
monitorInterval |
配置文件监控间隔(秒),0 表示不监控 | 30(30秒检查一次) |
示例:
<Configuration status="WARN" monitorInterval="30">
status="WARN": 只输出 WARN 及以上级别的 Log4j2 内部日志monitorInterval="30": 每 30 秒检查一次配置文件是否有更新,支持热更新
3.3.2 Properties 属性定义
<Properties>
<!-- 日志文件存储目录 -->
<Property name="LOG_HOME">logs</Property>
<!-- 日志文件名称前缀 -->
<Property name="LOG_FILE_NAME">monitor</Property>
<!-- 日志输出格式 -->
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
格式说明:
%d{yyyy-MM-dd HH:mm:ss.SSS}: 日期时间(精确到毫秒)[%t]: 线程名%-5level: 日志级别(左对齐,5个字符宽度)%logger{36}: 类名(最多36个字符,超出部分用…表示)%msg: 日志消息%n: 换行符
3.4 Appenders(输出器)详解
3.4.1 Console Appender(控制台输出)
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}"/>
<ThresholdFilter level="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
属性说明:
name: Appender 名称(用于 Logger 引用)target: 输出目标,SYSTEM_OUT(标准输出)或SYSTEM_ERR(标准错误)
过滤器说明:
ThresholdFilter: 阈值过滤器level="INFO": 只接受 INFO 及以上级别onMatch="ACCEPT": 匹配时接受onMismatch="DENY": 不匹配时拒绝
3.4.2 RollingFile Appender(滚动文件输出)
<RollingFile name="FileAppender"
fileName="${LOG_HOME}/${LOG_FILE_NAME}.log"
filePattern="${LOG_HOME}/${LOG_FILE_NAME}-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<!-- 基于时间的滚动策略:每天滚动 -->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!-- 基于文件大小的滚动策略:超过 10MB 滚动 -->
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<!-- 保留最近 30 天的日志文件 -->
<DefaultRolloverStrategy max="30"/>
</RollingFile>
属性说明:
fileName: 当前日志文件路径filePattern: 滚动后的日志文件命名模式%d{yyyy-MM-dd}: 日期格式%i: 序号(同一天多个文件时使用)
滚动策略:
TimeBasedTriggeringPolicy: 基于时间的滚动interval="1": 每 1 个时间单位滚动一次modulate="true": 在时间边界(如 0 点)滚动
SizeBasedTriggeringPolicy: 基于文件大小的滚动size="10MB": 文件超过 10MB 时滚动
保留策略:
DefaultRolloverStrategy: 默认滚动策略max="30": 保留最近 30 个文件(或 30 天)
3.4.3 错误日志单独输出
<RollingFile name="ErrorFileAppender"
fileName="${LOG_HOME}/${LOG_FILE_NAME}-error.log"
filePattern="${LOG_HOME}/${LOG_FILE_NAME}-error-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${LOG_PATTERN}"/>
<!-- 只输出 ERROR 级别的日志 -->
<ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
3.4.4 SQL 日志单独输出
<RollingFile name="SqlFileAppender"
fileName="${LOG_HOME}/${LOG_FILE_NAME}-sql.log"
filePattern="${LOG_HOME}/${LOG_FILE_NAME}-sql-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
3.5 Loggers(日志记录器)详解
3.5.1 Logger 配置
<Logger name="pdfc.monitor" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
<AppenderRef ref="ErrorFileAppender"/>
</Logger>
属性说明:
name: Logger 名称(通常是包名或类名)level: 日志级别(TRACE < DEBUG < INFO < WARN < ERROR < FATAL)additivity="false": 不继承父 Logger 的 Appender(避免重复输出)
AppenderRef:
ref: 引用已定义的 Appender 名称
3.5.2 Root Logger
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
<AppenderRef ref="ErrorFileAppender"/>
</Root>
说明:
RootLogger 是所有 Logger 的父 Logger- 没有指定 Logger 的类会使用 Root Logger 的配置
RootLogger 不能设置additivity(默认为 true)
3.5.3 项目中的 Logger 配置
<!-- 项目包日志级别 -->
<Logger name="pdfc.monitor" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
<AppenderRef ref="ErrorFileAppender"/>
</Logger>
<!-- DAO 层 SQL 日志 -->
<Logger name="pdfc.monitor.domain.sys.dao" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
<AppenderRef ref="SqlFileAppender"/>
</Logger>
<!-- Spring 框架日志 -->
<Logger name="org.springframework" level="INFO" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
</Logger>
<!-- 数据库连接池日志 -->
<Logger name="com.zaxxer.hikari" level="INFO" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
</Logger>
<!-- JDBC 日志 -->
<Logger name="org.springframework.jdbc" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
<AppenderRef ref="SqlFileAppender"/>
</Logger>
四、代码中的使用方式
4.1 获取 Logger 实例
方式一:使用 LogManager(推荐)
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class SysUserController {
// 使用 static final 修饰,避免重复创建
private static final Logger logger = LogManager.getLogger(SysUserController.class);
public void someMethod() {
logger.info("这是一条日志");
}
}
方式二:使用 Lombok @Slf4j(可选)
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class MonitorMybatisConfig {
public void someMethod() {
// 使用 log 变量(Lombok 自动生成)
log.info("这是一条日志");
}
}
注意:
- 如果使用
@Slf4j,需要确保项目中有slf4j-api依赖 - Log4j2 已经包含了
log4j-slf4j-impl,可以直接使用@Slf4j - 但项目中使用的是原生 Log4j2 API(
LogManager),性能更好
4.2 日志级别使用
4.2.1 日志级别说明
| 级别 | 说明 | 使用场景 | 示例 |
|---|---|---|---|
| TRACE | 跟踪 | 最详细的调试信息,通常只在开发时使用 | 方法进入/退出、变量值 |
| DEBUG | 调试 | 详细的调试信息,用于开发调试 | SQL 语句、参数值、执行流程 |
| INFO | 信息 | 重要的业务流程信息 | 接口调用、操作成功、关键节点 |
| WARN | 警告 | 警告信息,不影响系统运行 | 参数校验失败、业务警告 |
| ERROR | 错误 | 错误信息,需要关注 | 异常、系统错误 |
| FATAL | 致命 | 致命错误,可能导致系统崩溃 | 系统无法恢复的错误 |
4.2.2 日志级别使用示例
public class SysUserController {
private static final Logger logger = LogManager.getLogger(SysUserController.class);
@PostMapping("/add")
public ApiResponse<Integer> add(@RequestBody SysUserVo userVo) {
// INFO: 记录重要业务流程(接口调用)
logger.info("收到新增用户请求,用户信息: {}", userVo);
try {
int result = sysUserService.insert(userVo);
if (result > 0) {
// INFO: 操作成功
logger.info("新增用户成功,用户ID: {}", userVo.getId());
return new ApiResponse<Integer>(result, "新增成功", result);
} else {
// WARN: 业务警告(操作失败但不影响系统)
logger.warn("新增用户失败,返回结果: {}", result);
return new ApiResponse<Integer>(-1, "新增失败", result);
}
} catch (Exception e) {
// ERROR: 异常信息
logger.error("新增用户异常,用户信息: {}", userVo, e);
return new ApiResponse<Integer>(-1, "新增失败: " + e.getMessage(), 0);
}
}
}
public class SysUserServiceImpl {
private static final Logger logger = LogManager.getLogger(SysUserServiceImpl.class);
public int insert(SysUserVo entity) {
// DEBUG: 详细的执行流程
logger.debug("开始执行新增用户操作,用户信息: {}", entity);
if (entity == null) {
// WARN: 参数校验失败
logger.warn("新增用户失败,用户信息为空");
return 0;
}
try {
// DEBUG: 参数转换
SysUser po = BeanConverter.voToPo(entity);
logger.debug("转换后的PO对象: {}", po);
int result = sysUserDao.insert(po);
// DEBUG: 执行结果
logger.debug("新增用户操作完成,影响行数: {}", result);
return result;
} catch (Exception e) {
// ERROR: 异常信息(包含堆栈)
logger.error("新增用户操作异常,用户信息: {}", entity, e);
throw e;
}
}
}
4.3 参数化日志(推荐)
4.3.1 使用占位符
// ✅ 正确:使用占位符(推荐)
logger.info("收到新增用户请求,用户ID: {},用户名: {}", userId, userName);
// ❌ 错误:字符串拼接(不推荐)
logger.info("收到新增用户请求,用户ID: " + userId + ",用户名: " + userName);
优势:
- 性能更好:只有在日志级别匹配时才会进行字符串拼接
- 代码更清晰:避免复杂的字符串拼接
- 支持对象:自动调用
toString()方法
4.3.2 异常日志
try {
// 业务代码
} catch (Exception e) {
// ✅ 正确:将异常作为最后一个参数
logger.error("新增用户异常,用户信息: {}", userVo, e);
// ❌ 错误:不要将异常放在消息中
logger.error("新增用户异常: " + e.getMessage());
}
说明:
- 异常对象作为最后一个参数时,Log4j2 会自动打印异常堆栈
- 如果异常在消息字符串中,只会打印异常消息,不会打印堆栈
4.4 各层日志使用规范
4.4.1 Controller 层
日志级别: INFO
记录内容:
- ✅ 请求接收日志(包含请求参数)
- ✅ 操作成功日志(包含结果信息)
- ✅ 操作失败日志(包含失败原因)
- ✅ 异常日志(包含异常堆栈)
示例:
@RestController
@RequestMapping("/api/sys/user")
public class SysUserController {
private static final Logger logger = LogManager.getLogger(SysUserController.class);
@PostMapping("/add")
public ApiResponse<Integer> add(@RequestBody SysUserVo userVo) {
logger.info("收到新增用户请求,用户信息: {}", userVo);
try {
int result = sysUserService.insert(userVo);
if (result > 0) {
logger.info("新增用户成功,用户ID: {}", userVo.getId());
return new ApiResponse<Integer>(result, "新增成功", result);
} else {
logger.warn("新增用户失败,返回结果: {}", result);
return new ApiResponse<Integer>(-1, "新增失败", result);
}
} catch (Exception e) {
logger.error("新增用户异常,用户信息: {}", userVo, e);
return new ApiResponse<Integer>(-1, "新增失败: " + e.getMessage(), 0);
}
}
}
4.4.2 Service 层
日志级别: DEBUG
记录内容:
- ✅ 方法开始执行日志
- ✅ 参数转换日志(VO → PO)
- ✅ 操作完成日志(包含影响行数)
- ✅ 异常日志(包含异常堆栈)
示例:
@Service
public class SysUserServiceImpl implements SysUserService {
private static final Logger logger = LogManager.getLogger(SysUserServiceImpl.class);
public int insert(SysUserVo entity) {
logger.debug("开始执行新增用户操作,用户信息: {}", entity);
if (entity == null) {
logger.warn("新增用户失败,用户信息为空");
return 0;
}
try {
SysUser po = BeanConverter.voToPo(entity);
logger.debug("转换后的PO对象: {}", po);
int result = sysUserDao.insert(po);
logger.debug("新增用户操作完成,影响行数: {}", result);
return result;
} catch (Exception e) {
logger.error("新增用户操作异常,用户信息: {}", entity, e);
throw e;
}
}
}
4.4.3 DAO 层
日志级别: DEBUG(由 MyBatis 自动记录)
记录内容:
- ✅ SQL 语句日志(MyBatis 自动记录)
- ✅ SQL 参数日志(MyBatis 自动记录)
- ✅ 执行结果日志(MyBatis 自动记录)
说明:
- DAO 层通常不需要手动记录日志
- MyBatis 会自动记录 SQL 执行日志
- 如果需要,可以在 Mapper XML 中添加注释
MyBatis SQL 日志配置:
# application.properties
mybatis.configuration.log-impl=org.apache.ibatis.logging.slf4j.Slf4jImpl
五、日志文件管理
5.1 日志文件位置
开发环境
日志文件保存在项目根目录下的 logs/ 目录:
monitor_java/
├── logs/
│ ├── monitor.log # 所有日志
│ ├── monitor-sql.log # SQL日志
│ ├── monitor-error.log # 错误日志
│ ├── monitor-2025-11-13-1.log # 滚动日志(按日期和序号)
│ └── ...
生产环境
建议将日志文件配置到独立的日志目录:
Linux:
<Property name="LOG_HOME">/var/log/monitor</Property>
Windows:
<Property name="LOG_HOME">C:\logs\monitor</Property>
5.2 日志文件滚动策略
5.2.1 滚动触发条件
- 时间滚动: 每天 0 点自动滚动
- 大小滚动: 文件超过 10MB 时滚动
- 同时满足: 满足任一条件即滚动
5.2.2 滚动文件命名
当前文件: monitor.log
滚动后文件: monitor-2025-11-13-1.log
monitor: 文件名称前缀2025-11-13: 日期(yyyy-MM-dd)1: 序号(同一天多个文件时递增)
示例:
monitor.log # 当前日志文件
monitor-2025-11-13-1.log # 2025-11-13 的第一个滚动文件
monitor-2025-11-13-2.log # 2025-11-13 的第二个滚动文件(如果超过大小)
monitor-2025-11-14-1.log # 2025-11-14 的第一个滚动文件
5.3 日志文件保留策略
保留天数: 30 天
说明:
DefaultRolloverStrategy max="30"表示保留最近 30 个文件- 如果按天滚动,则保留 30 天的日志
- 如果按大小滚动,则保留最近 30 个文件
修改保留天数:
<DefaultRolloverStrategy max="60"/> <!-- 改为保留 60 天 -->
5.4 查看日志
5.4.1 实时查看日志
# 查看所有日志
tail -f logs/monitor.log
# 查看 SQL 日志
tail -f logs/monitor-sql.log
# 查看错误日志
tail -f logs/monitor-error.log
5.4.2 搜索日志
# 搜索特定用户的日志
grep "日志测试用户" logs/monitor.log
# 搜索错误日志
grep "ERROR" logs/monitor.log
# 搜索特定接口的日志
grep "新增用户" logs/monitor.log
# 搜索特定时间段的日志(需要日志格式包含时间)
grep "2025-11-13 14:" logs/monitor.log
5.4.3 查看日志文件大小
# 查看日志文件大小
ls -lh logs/
# 查看日志文件总大小
du -sh logs/
六、最佳实践
6.1 日志级别选择
6.1.1 开发环境
<!-- 开发环境:使用 DEBUG 级别,便于调试 -->
<Logger name="pdfc.monitor" level="DEBUG" additivity="false">
...
</Logger>
6.1.2 生产环境
<!-- 生产环境:使用 INFO 级别,减少日志量 -->
<Logger name="pdfc.monitor" level="INFO" additivity="false">
...
</Logger>
建议:
- 开发环境:使用 DEBUG 级别,便于调试
- 测试环境:使用 INFO 级别,平衡日志量和调试需求
- 生产环境:使用 INFO 级别,减少日志量,提高性能
6.2 日志内容规范
6.2.1 日志消息格式
// ✅ 正确:包含上下文信息
logger.info("收到新增用户请求,用户ID: {},用户名: {}", userId, userName);
// ❌ 错误:缺少上下文信息
logger.info("收到请求");
6.2.2 敏感信息处理
// ❌ 错误:不要记录敏感信息
logger.info("用户登录,密码: {}", password);
// ✅ 正确:脱敏处理
logger.info("用户登录,用户名: {}", userName);
敏感信息包括:
- 密码、密钥、Token
- 身份证号、银行卡号
- 手机号(可部分脱敏)
- 其他个人隐私信息
6.3 性能优化
6.3.1 使用参数化日志
// ✅ 正确:参数化日志(性能好)
logger.debug("查询用户,用户ID: {},条件: {}", userId, condition);
// ❌ 错误:字符串拼接(性能差)
logger.debug("查询用户,用户ID: " + userId + ",条件: " + condition);
原因:
- 参数化日志只有在日志级别匹配时才会进行字符串拼接
- 字符串拼接无论日志级别如何都会执行
6.3.2 避免在循环中记录日志
// ❌ 错误:在循环中记录日志
for (User user : userList) {
logger.debug("处理用户: {}", user); // 如果日志级别是 DEBUG,会产生大量日志
}
// ✅ 正确:在循环外记录日志
logger.debug("开始处理用户列表,数量: {}", userList.size());
for (User user : userList) {
// 处理用户
}
logger.debug("用户列表处理完成");
6.3.3 使用异步日志(可选)
如果需要更高的性能,可以配置异步日志:
<!-- 添加异步日志依赖 -->
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.4</version>
</dependency>
<!-- 配置异步 Logger -->
<AsyncLogger name="pdfc.monitor" level="DEBUG" includeLocation="true">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
</AsyncLogger>
6.4 日志格式规范
6.4.1 统一日志格式
项目中使用统一的日志格式:
%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
输出示例:
2025-11-13 14:30:25.123 [http-nio-8080-exec-1] INFO pdfc.monitor.web.SysUserController - 收到新增用户请求,用户信息: SysUserVo(id=null, name=测试用户, work=工程师, age=25)
6.4.2 自定义日志格式(可选)
如果需要自定义日志格式,可以修改 LOG_PATTERN:
<!-- 添加方法名和行号 -->
<Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}.%M(%L) - %msg%n</Property>
格式说明:
%M: 方法名%L: 行号%F: 文件名
注意: 添加方法名和行号会影响性能,生产环境不推荐使用。
七、常见问题
7.1 日志不输出
问题:日志文件没有生成
可能原因:
- 日志目录不存在或没有写权限
- 日志级别配置过高
- Logger 名称不匹配
解决方法:
- 检查日志目录是否存在,是否有写权限
- 检查日志级别配置
- 检查 Logger 名称是否匹配(包名或类名)
问题:控制台没有日志输出
可能原因:
- Console Appender 的过滤器级别过高
- Logger 的
additivity="false"但没有引用 Console Appender
解决方法:
- 检查
ThresholdFilter的级别 - 确保 Logger 引用了 Console Appender
7.2 日志重复输出
问题:同一条日志输出多次
可能原因:
- Logger 的
additivity="true"(默认),会继承父 Logger 的 Appender - 同一个 Appender 被多个 Logger 引用
解决方法:
<!-- 设置 additivity="false",不继承父 Logger 的 Appender -->
<Logger name="pdfc.monitor" level="DEBUG" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
</Logger>
7.3 日志文件过大
问题:日志文件占用磁盘空间过大
解决方法:
- 调整日志级别(生产环境使用 INFO)
- 减小日志文件大小限制
- 减少日志保留天数
- 定期清理旧日志文件
<!-- 减小文件大小限制 -->
<SizeBasedTriggeringPolicy size="5MB"/>
<!-- 减少保留天数 -->
<DefaultRolloverStrategy max="7"/>
7.4 配置文件不生效
问题:修改配置文件后不生效
解决方法:
- 检查配置文件名称和位置是否正确
- 检查配置文件语法是否正确(XML 格式)
- 重启应用(如果
monitorInterval="0") - 检查
monitorInterval配置(支持热更新)
<!-- 启用配置文件监控(30秒检查一次) -->
<Configuration status="WARN" monitorInterval="30">
7.5 Logback 冲突
问题:启动时出现 Logback 相关错误
可能原因:
- 没有排除
spring-boot-starter-logging - 第三方依赖引入了 logback
解决方法:
- 确保排除了
spring-boot-starter-logging - 排除第三方依赖中的 logback:
<dependency>
<groupId>ins.framework</groupId>
<artifactId>ins-framework-mybatis</artifactId>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</exclusion>
</exclusions>
</dependency>
八、配置调整示例
8.1 修改日志级别
<!-- 将 Service 层日志级别改为 INFO -->
<Logger name="pdfc.monitor.service.impl" level="INFO" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
<AppenderRef ref="ErrorFileAppender"/>
</Logger>
8.2 修改日志文件大小
<!-- 将文件大小限制改为 50MB -->
<SizeBasedTriggeringPolicy size="50MB"/>
8.3 修改日志保留天数
<!-- 将保留天数改为 60 天 -->
<DefaultRolloverStrategy max="60"/>
8.4 添加新的日志文件
<!-- 添加业务日志文件 -->
<RollingFile name="BusinessFileAppender"
fileName="${LOG_HOME}/${LOG_FILE_NAME}-business.log"
filePattern="${LOG_HOME}/${LOG_FILE_NAME}-business-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<SizeBasedTriggeringPolicy size="10MB"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
<!-- 在 Logger 中引用 -->
<Logger name="pdfc.monitor.service" level="INFO" additivity="false">
<AppenderRef ref="Console"/>
<AppenderRef ref="FileAppender"/>
<AppenderRef ref="BusinessFileAppender"/>
</Logger>
九、总结
9.1 核心要点
- 依赖配置: 必须排除 logback,添加 log4j2
- 配置文件:
log4j2.xml放在src/main/resources/目录 - 日志级别: 开发环境 DEBUG,生产环境 INFO
- 参数化日志: 使用占位符
{},不要字符串拼接 - 异常日志: 异常对象作为最后一个参数
- 日志文件: 配置滚动策略和保留策略
9.2 项目配置总结
✅ 已完成的配置:
- ✅ 依赖已添加(排除 logback,使用 log4j2)
- ✅ 配置文件已创建(log4j2.xml)
- ✅ Controller 层日志已添加(INFO 级别)
- ✅ Service 层日志已添加(DEBUG 级别)
- ✅ DAO 层日志已配置(MyBatis 自动记录)
- ✅ 日志文件正常生成(monitor.log、monitor-sql.log、monitor-error.log)
- ✅ 日志滚动策略已配置(按时间和大小滚动)
- ✅ 日志保留策略已配置(保留 30 天)
9.3 使用建议
- 开发阶段: 使用 DEBUG 级别,便于调试
- 生产阶段: 使用 INFO 级别,减少日志量
- 异常处理: 始终记录异常堆栈
- 敏感信息: 不要记录密码、密钥等敏感信息
- 性能考虑: 使用参数化日志,避免在循环中记录日志
- 日志管理: 定期清理旧日志文件,避免磁盘空间不足
文档版本: 1.0
最后更新: 2025-11-13
维护者: 项目团队
更多推荐
所有评论(0)