Spring Boot 日志系统实战:从配置到最佳实践
在现代软件开发中,日志系统是保障应用稳定性和可维护性的关键组件。本文将基于我们项目中的日志配置文件,详细介绍 Spring Boot 中日志系统的配置与使用,特别适合之前缺乏日志使用经验的开发者。
一、日志系统概述
Spring Boot 默认使用 SLF4J(Simple Logging Facade for Java)作为日志门面,配合 Logback 作为日志实现。这种设计的优势在于:
- 解耦 :应用代码只依赖 SLF4J 接口,不直接依赖具体的日志实现
- 灵活性 :可以随时切换不同的日志实现(如 Logback、Log4j2 等)
- 统一 :为所有框架提供统一的日志输出方式
二、Logback 配置详解
我们项目中的日志配置文件是 logback-spring.xml ,位于 src/main/resources 目录下。下面详细解释各配置项的作用。
1. 基本配置结构
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 配置内容 -->
</configuration>
这是 Logback 配置文件的基本结构,所有配置都包含在 <configuration> 标签内。
2. 属性定义
<!-- 日志格式定义 -->
<property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS}
[%thread] %-5level %logger{50} - %msg%n"/>
<!-- 日志文件存储路径 -->
<property name="LOG_FILE_PATH" value="${user.dir}/logs"/>
- LOG_PATTERN :定义日志输出格式,包含时间戳、线程名、日志级别、类名和日志消息
- LOG_FILE_PATH :定义日志文件的存储路径,使用 ${user.dir} 变量表示项目根目录
3. 控制台输出配置
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
- appender :日志输出目的地,这里配置的是控制台输出
- name :appender 的名称,用于后续引用
- class :指定使用的 appender 实现类, ConsoleAppender 用于控制台输出
- encoder :编码器,负责将日志事件转换为字符串
- pattern :使用之前定义的日志格式
- charset :指定日志输出的字符集,确保中文显示正常
4. 文件输出配置
<appender name="FILE" class="ch.qos.logback.core.rolling.
RollingFileAppender">
<file>${LOG_FILE_PATH}/application.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.
TimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE_PATH}/application.%d{yyyy-MM-dd}.
log.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
<triggeringPolicy class="ch.qos.logback.core.rolling.
SizeBasedTriggeringPolicy">
<maxFileSize>10MB</maxFileSize>
</triggeringPolicy>
</appender>
- RollingFileAppender :支持日志文件滚动的文件输出 appender
- file :指定当前日志文件的路径
- rollingPolicy :日志文件滚动策略
- TimeBasedRollingPolicy :基于时间的滚动策略
- fileNamePattern :滚动文件的命名格式,这里配置为每天生成一个新文件,并使用 gzip 压缩
- maxHistory :保留日志文件的天数
- triggeringPolicy :触发文件滚动的条件
- SizeBasedTriggeringPolicy :基于文件大小的触发策略
- maxFileSize :单个日志文件的最大大小
5. 错误日志分离
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.
RollingFileAppender">
<file>${LOG_FILE_PATH}/error.log</file>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.
TimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE_PATH}/error.%d{yyyy-MM-dd}.log.gz</
fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
<triggeringPolicy class="ch.qos.logback.core.rolling.
SizeBasedTriggeringPolicy">
<maxFileSize>5MB</maxFileSize>
</triggeringPolicy>
</appender>
- filter :日志过滤器,这里使用 ThresholdFilter 只记录 ERROR 级别及以上的日志
- 其他配置与普通日志文件类似,但错误日志文件大小限制为 5MB
6. 日志级别配置
<!-- 不同包的日志级别配置 -->
<logger name="com.example" level="DEBUG"/>
<logger name="org.springframework.web" level="INFO"/>
<logger name="org.springframework.security" level="INFO"/>
<logger name="org.springframework.boot" level="INFO"/>
<logger name="org.apache.ibatis" level="INFO"/>
<logger name="com.baomidou" level="INFO"/>
<!-- 根日志级别配置 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
<appender-ref ref="ERROR_FILE"/>
</root>
- logger :配置特定包或类的日志级别
- name :指定包名或类名
- level :指定日志级别(TRACE < DEBUG < INFO < WARN < ERROR)
- root :根日志配置,默认应用于所有未指定日志级别的包
- appender-ref :引用之前定义的 appender,将日志输出到对应目的地
三、@Slf4j 注解的使用
1. 基本使用
在我们的项目中,很多类都使用了 @Slf4j 注解,例如 ChildrenServiceImpl.java :
@Service
@Slf4j
public class ChildrenServiceImpl extends ServiceImpl<ChildrenMapper,
Children> implements ChildrenService {
// 业务代码
}
使用 @Slf4j 注解后,就可以直接在类中使用 log 对象记录日志:
log.debug("这是一条DEBUG级别日志");
log.info("这是一条INFO级别日志");
log.warn("这是一条WARN级别日志");
log.error("这是一条ERROR级别日志");
2. 原理
@Slf4j 是 Lombok 提供的一个注解,它的工作原理是:
1. 在编译时,Lombok 会自动为带有 @Slf4j 注解的类生成以下代码:
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ChildrenServiceImpl.class);
2. 这样就避免了手动创建 logger 对象的重复代码
3. 依赖配置
要使用 @Slf4j 注解,需要在 pom.xml 中添加 Lombok 依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version> <!-- 显式指定版本 -->
<optional>true</optional>
</dependency>
同时,需要在 IDE 中安装 Lombok 插件,以支持注解的识别和自动补全。
四、日志使用最佳实践
1. 选择合适的日志级别

2. 日志内容规范
- 清晰明确 :日志消息应该清晰地表达发生了什么
- 包含上下文 :记录关键参数、用户ID、订单ID等,便于问题定位
- 避免敏感信息 :不要记录密码、身份证号等敏感数据
- 结构化 :尽量使用固定格式,便于日志分析工具解析
反例 :
log.info("用户操作"); // 过于模糊,没有上下文
正例 :
log.info("用户[{}]完成订单[{}]支付,金额:{}", userId, orderId, amount); // 包含关键上下文信息
3. 异常日志处理
记录异常时,应该包含异常堆栈信息,便于问题排查:
错误示例 :
try {
// 业务代码
} catch (Exception e) {
log.error("操作失败:" + e.getMessage()); // 丢失堆栈信息
}
正确示例 :
try {
// 业务代码
} catch (Exception e) {
log.error("用户[{}]操作订单[{}]失败", userId, orderId, e); // 包含堆栈信
息
}
4. 性能考虑
- 避免不必要的日志 :在生产环境中,避免输出过多的 DEBUG 级别日志
- 字符串拼接 :使用 SLF4J 的参数化日志,避免不必要的字符串拼接
// 不推荐
log.debug("用户ID:" + userId + ",订单ID:" + orderId);
// 推荐
log.debug("用户ID:{},订单ID:{}", userId, orderId);
- 条件日志 :对于复杂的日志内容,可以先检查日志级别
if (log.isDebugEnabled()) {
String complexInfo = generateComplexInfo(); // 复杂计算
log.debug("复杂信息:{}", complexInfo);
}
浙公网安备 33010602011771号