日志技术
Path Intellisense
学习目标
- 能用自己的话说明什么是日志、为什么要在程序中记录日志。
- 能说出为什么不用 System.out.println 记录日志,以及专业日志框架带来的好处。
- 了解常见日志框架(JUL、Log4j、Logback、Slf4j)及其关系;必须掌握 Slf4j + Logback 在 Spring Boot 中的使用。
- 能在 Spring Boot 中引入/配置 Logback(控制台 + 文件),并理解日志级别与配置方式。
- 能在 Controller/Service 中使用 @Slf4j 与 log.info/debug 等规范记录日志,并知道占位符
{}的用法。
1. 从零开始:什么是日志?为什么要在程序中记录日志?
1.1 是什么
日志就像程序里的「日记」:用来记录应用的运行信息、状态信息、错误信息。
谁在什么时候做了什么、结果如何、有没有报错,都可以通过日志追溯。
1.2 为什么
在程序中记录日志可以:
- 追踪数据与执行过程:便于复盘请求链路、数据变化。
- 性能优化:通过耗时、调用次数等日志做分析与优化。
- 排查问题:出问题时,日志是定位错误原因的第一手资料。
- 监控运行状态:配合监控系统,发现异常、告警。
1.3 小结
- 日志 = 程序的运行/状态/错误记录。
- 用途:追踪、优化、排错、监控。
2. 为什么不用 System.out.println 记录日志?
用 System.out.println(...) 虽然能「打出一行字」,但存在明显问题:
| 问题 | 说明 |
|---|---|
| 硬编码 | 想不输出某条日志,只能删代码或注释,无法通过配置灵活开关。 |
| 只能输出到控制台 | 无法同时输出到文件、无法按日期/大小滚动、无法区分环境。 |
| 不便于扩展与维护 | 无法统一格式、级别、输出目标,不利于团队协作和线上排查。 |
因此,项目开发中应使用专业日志框架,通过配置控制输出位置、格式、级别,而无需改代码。
3. 常见日志框架简介(了解即可)

| 框架 | 说明 |
|---|---|
| JUL | Java 自带的日志框架(java.util.logging),配置简单但不够灵活,性能一般。 |
| Log4j | 早期流行框架,支持多种输出目标和配置方式。 |
| Logback | 可视为 Log4j 的升级版,功能更多、性能更好,与 Slf4j 配合默契。 |
| Slf4j | Simple Logging Facade for Java:一套门面/接口,不负责具体打日志,而是让程序「面向接口编程」,底层可切换为 Logback、Log4j 等。 |
必须掌握:在 Spring Boot 中,我们通常使用 Slf4j(门面)+ Logback(实现),代码里只依赖 Slf4j 的 API(如 LoggerFactory.getLogger、log.info),具体输出由 Logback 完成。
4. Logback 入门(是什么、怎么做)
4.1 为什么选 Logback
- Spring Boot 默认已集成 Logback,无需额外引入依赖(starter 已传递)。
- 配置灵活:控制台、文件、级别、格式均可通过配置文件控制。
- 性能优于 Log4j,与 Slf4j 无缝配合。
4.2 准备工作(两步)
1)依赖
Spring Boot 项目中一般无需单独引入 Logback;若为纯 Java 项目,可引入:
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.11</version>
</dependency>2)配置文件
在 src/main/resources 下新建 logback.xml(Spring Boot 会自动识别),例如:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
</encoder>
</appender>
<root level="ALL">
<appender-ref ref="STDOUT" />
</root>
</configuration>%d日期;%thread线程名;%-5level级别(左对齐 5 字符);%logger{50}类名;%msg日志内容;%n换行。
4.3 Logback 记录日志的步骤
使用 Logback 记录日志,可以归纳为两步:
- 引入 Logback 的依赖、配置文件 logback.xml(见上文 4.2 准备工作)。
- 定义日志记录对象 Logger,调用方法(debug / info / …)记录日志(见下方示例)。
4.4 示例:定义 Logger 并调用
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogTest {
// 定义日志记录对象
private static final Logger log = LoggerFactory.getLogger(LogTest.class);
@Test
public void testLog() {
log.debug("开始计算...");
int sum = 0;
int[] nums = {1, 5, 3, 2, 1, 4, 5, 4, 6, 7, 4, 34, 2, 23};
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
log.info("计算结果为: " + sum);
log.debug("结束计算...");
}
}注意:循环遍历数组时,条件应写
i < nums.length,不要写成i <= nums.length,否则最后一次会访问nums[nums.length],引发ArrayIndexOutOfBoundsException。 [] 运行后,控制台会输出时间、线程名、级别、类名、消息,例如:
2025-02-03 10:00:00.123 [main] DEBUG c.i.LogTest-开始计算...
2025-02-03 10:00:00.124 [main] INFO c.i.LogTest-计算结果为: 106
2025-02-03 10:00:00.124 [main] DEBUG c.i.LogTest-结束计算...控制台输出效果示意:

4.5 常见坑
- 没有 logback.xml:若需自定义,务必放在
src/main/resources下,且文件名正确。 - Logger 拿错类:
LoggerFactory.getLogger(LogTest.class)建议传入当前类,便于定位输出位置。 - 只记得 System.out:养成习惯用
log.info/debug/error,便于后续按级别过滤和统一管理。
5. Logback 配置文件详解
5.1 配置文件说明
- 配置文件名:
logback.xml。 - 作用:该配置文件是对 Logback 日志框架输出的日志进行控制的,可以配置输出的格式、位置及日志开关等。
- 常用的两种输出日志的位置:控制台、系统文件。
下面分别说明如何配置这两种输出,以及如何通过 root 开启/关闭日志。
5.2 输出到控制台
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
</encoder>
</appender>5.3 输出到系统文件(按天 + 按大小滚动)
<!-- 系统文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>D:/tlias-%d{yyyy-MM-dd}-%i.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
</encoder>
</appender>FileNamePattern:文件名规则,%d日期,%i序号(同一天多文件时)。MaxHistory:最多保留 30 天历史。maxFileSize:单文件超过 10MB 滚动到新文件。
生产环境可把 D:/ 改为服务器目录,如 /var/log/app/。
5.4 日志开关:root 与 appender-ref
- 开启日志:
level="ALL"(输出所有级别)。 - 关闭日志:
level="OFF"(不输出任何日志)。
在 <root> 中通过 appender-ref 引用上面定义的 STDOUT(控制台)和 FILE(系统文件),即可同时输出到两处:
<root level="ALL">
<!-- 输出到控制台 -->
<appender-ref ref="STDOUT" />
<!-- 输出到文件 -->
<appender-ref ref="FILE" />
</root>appender-ref ref="STDOUT":将日志输出到控制台。appender-ref ref="FILE":将日志输出到系统文件。
6. Logback 日志级别(必须掌握)
日志级别指的是日志信息的类型,日志都会分级别。常见日志级别如下(级别由低到高):
| 日志级别 | 说明 | 记录方式 |
|---|---|---|
| trace | 追踪,记录程序运行轨迹。【使用很少】 | log.trace("...") |
| debug | 调试,记录程序调试过程中的信息;实际应用中一般将其视为最低级别。【使用较多】 | log.debug("...") |
| info | 记录一般信息,描述程序运行的关键事件,如:网络连接、IO 操作。【使用较多】 | log.info("...") |
| warn | 警告信息,记录潜在有害的情况。【使用较多】 | log.warn("...") |
| error | 错误信息。【使用较多】 | log.error("...") |
在 logback.xml 中配置 root 的 level 后,只有大于等于该级别的日志才会被输出。例如配置 level="info" 时,只会输出 INFO、WARN、ERROR,不输出 TRACE、DEBUG。
在 logback.xml 中控制 root 级别示例:
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>即:只输出 INFO、WARN、ERROR,不输出 TRACE、DEBUG。
开发时可设为 level="debug" 便于排查;上线后常设为 info 或 warn,减少噪音与 I/O。
7. 案例:在 Controller 中用 @Slf4j 记录日志
实际项目中,我们更推荐用 Lombok 的 @Slf4j 自动生成 log 对象,避免每个类手写 Logger。
7.1 引入 Lombok(若项目未有)
Spring Boot 项目通常已包含 Lombok;否则在 pom.xml 中:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>7.2 使用 @Slf4j 与占位符
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RequestMapping("/depts")
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping
public Result list() {
log.info("查询部门列表");
List<Dept> deptList = deptService.findAll();
return Result.success(deptList);
}
@DeleteMapping
public Result delete(Integer id) {
log.info("根据id删除部门, id: {}", id);
deptService.deleteById(id);
return Result.success();
}
@PostMapping
public Result save(@RequestBody Dept dept) {
log.info("新增部门, dept: {}", dept);
deptService.save(dept);
return Result.success();
}
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
log.info("根据ID查询, id: {}", id);
Dept dept = deptService.getById(id);
return Result.success(dept);
}
@PutMapping
public Result update(@RequestBody Dept dept) {
log.info("修改部门, dept: {}", dept);
deptService.update(dept);
return Result.success();
}
}要点:
- @Slf4j:Lombok 会在编译期生成
private static final Logger log = LoggerFactory.getLogger(DeptController.class);,无需手写。 - 占位符
{}:用log.info("删除部门, id: {}", id)而不是"id: " + id,便于日志框架做延迟拼接(例如当前级别不输出时可不拼接字符串),且格式统一。
7.3 常见错误与误区
- 用字符串拼接代替占位符:如
log.info("id=" + id),在关闭 INFO 时仍会做字符串拼接,建议改为log.info("id: {}", id)。 - 在 Controller 里不打日志:关键入口(如增删改查入口)建议至少打一条 INFO,便于追踪请求与排错。
- 敏感信息写进日志:密码、手机号等不要明文输出,可脱敏或直接不记录。
8. 核心执行总结(最小可执行)
- 为什么用日志:追踪、优化、排错、监控;不用
System.out.println,用日志框架。 - 技术选型:Spring Boot 默认 Slf4j + Logback,代码只依赖 Slf4j API。
- 配置:在
src/main/resources下放 logback.xml,配置控制台/文件 appender 和<root level="...">。 - 使用:类上加 @Slf4j,用
log.info/debug/error("消息", 占位符...),优先用{}占位符。 - 级别:生产常用
info或warn,开发可用debug;只输出 ≥ 配置级别的日志。
9. 关键概念速记(考试背诵向)
- 日志:记录程序运行信息、状态信息、错误信息的载体。
- Slf4j:简单日志门面,提供统一 API;Logback:具体实现,负责输出。
- logback.xml:Logback 的配置文件,控制输出位置、格式、级别。
- Appender:输出目标(如 ConsoleAppender、RollingFileAppender)。
- 日志级别:TRACE < DEBUG < INFO < WARN < ERROR;配置某级别则输出 ≥ 该级别的日志。
- @Slf4j:Lombok 注解,自动生成
log对象,等价于LoggerFactory.getLogger(当前类.class)。
10. 思维导图(层级与关联)
mindmap
root(日志技术)
为什么用
追踪执行与数据
性能优化
排查问题
监控状态
为什么不用 System.out
硬编码
只能控制台
难扩展维护
常见框架
JUL
Log4j
Logback
Slf4j 门面
使用方式
logback.xml
控制台/文件 Appender
root level
@Slf4j + log.info/debug/error
级别
TRACE
DEBUG
INFO
WARN
ERROR11. 实际应用场景(3 则)
- 接口排查:在 Controller 关键入口用
log.info记录请求参数或关键 ID,出问题时根据时间戳和 ID 查日志、定位请求。 - 异常与错误:在 catch 块中
log.error("描述", e),保留堆栈,便于线上报错后根据 trace 排查。 - 性能与审计:对重要操作(如下单、支付)打 INFO 日志(含业务主键),便于后续做简单统计或审计追溯;敏感信息需脱敏。