日志
- 日志结构说明
- 日志持久化
- 日志滚动策略
- 日志框架
-
- 日志门面
- 日志实现
- 日志门面与实现的关系
- 注解输出日志:@Slf4j⭐
- [为什么使用 SLF4J + Logback?](#为什么使用 SLF4J + Logback?)
日志结构说明
一条完整的日志记录通常包含以下几个核心组成部分,它们共同构成了日志的结构,帮助开发者快速定位问题。
日志结构示意图:
#mermaid-svg-M0GaRheeoRdEmvNB{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-M0GaRheeoRdEmvNB .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-M0GaRheeoRdEmvNB .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-M0GaRheeoRdEmvNB .error-icon{fill:#552222;}#mermaid-svg-M0GaRheeoRdEmvNB .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-M0GaRheeoRdEmvNB .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-M0GaRheeoRdEmvNB .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-M0GaRheeoRdEmvNB .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-M0GaRheeoRdEmvNB .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-M0GaRheeoRdEmvNB .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-M0GaRheeoRdEmvNB .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-M0GaRheeoRdEmvNB .marker{fill:#333333;stroke:#333333;}#mermaid-svg-M0GaRheeoRdEmvNB .marker.cross{stroke:#333333;}#mermaid-svg-M0GaRheeoRdEmvNB svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-M0GaRheeoRdEmvNB p{margin:0;}#mermaid-svg-M0GaRheeoRdEmvNB .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-M0GaRheeoRdEmvNB .cluster-label text{fill:#333;}#mermaid-svg-M0GaRheeoRdEmvNB .cluster-label span{color:#333;}#mermaid-svg-M0GaRheeoRdEmvNB .cluster-label span p{background-color:transparent;}#mermaid-svg-M0GaRheeoRdEmvNB .label text,#mermaid-svg-M0GaRheeoRdEmvNB span{fill:#333;color:#333;}#mermaid-svg-M0GaRheeoRdEmvNB .node rect,#mermaid-svg-M0GaRheeoRdEmvNB .node circle,#mermaid-svg-M0GaRheeoRdEmvNB .node ellipse,#mermaid-svg-M0GaRheeoRdEmvNB .node polygon,#mermaid-svg-M0GaRheeoRdEmvNB .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-M0GaRheeoRdEmvNB .rough-node .label text,#mermaid-svg-M0GaRheeoRdEmvNB .node .label text,#mermaid-svg-M0GaRheeoRdEmvNB .image-shape .label,#mermaid-svg-M0GaRheeoRdEmvNB .icon-shape .label{text-anchor:middle;}#mermaid-svg-M0GaRheeoRdEmvNB .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-M0GaRheeoRdEmvNB .rough-node .label,#mermaid-svg-M0GaRheeoRdEmvNB .node .label,#mermaid-svg-M0GaRheeoRdEmvNB .image-shape .label,#mermaid-svg-M0GaRheeoRdEmvNB .icon-shape .label{text-align:center;}#mermaid-svg-M0GaRheeoRdEmvNB .node.clickable{cursor:pointer;}#mermaid-svg-M0GaRheeoRdEmvNB .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-M0GaRheeoRdEmvNB .arrowheadPath{fill:#333333;}#mermaid-svg-M0GaRheeoRdEmvNB .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-M0GaRheeoRdEmvNB .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-M0GaRheeoRdEmvNB .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-M0GaRheeoRdEmvNB .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-M0GaRheeoRdEmvNB .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-M0GaRheeoRdEmvNB .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-M0GaRheeoRdEmvNB .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-M0GaRheeoRdEmvNB .cluster text{fill:#333;}#mermaid-svg-M0GaRheeoRdEmvNB .cluster span{color:#333;}#mermaid-svg-M0GaRheeoRdEmvNB div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-M0GaRheeoRdEmvNB .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-M0GaRheeoRdEmvNB rect.text{fill:none;stroke-width:0;}#mermaid-svg-M0GaRheeoRdEmvNB .icon-shape,#mermaid-svg-M0GaRheeoRdEmvNB .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-M0GaRheeoRdEmvNB .icon-shape p,#mermaid-svg-M0GaRheeoRdEmvNB .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-M0GaRheeoRdEmvNB .icon-shape .label rect,#mermaid-svg-M0GaRheeoRdEmvNB .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-M0GaRheeoRdEmvNB .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-M0GaRheeoRdEmvNB .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-M0GaRheeoRdEmvNB :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 时间戳
日志级别
线程信息
记录器名称
日志消息
异常堆栈

1. 时间戳
记录日志事件发生的精确时间,通常包含日期和具体时间(精确到毫秒或微秒)。
- 格式示例 :
2026-05-23 20:35:48.123 - 作用:用于追溯问题发生的时间点,分析时间序列上的事件关联。
2. 日志级别
标识日志事件的严重程度,是日志分类和过滤的关键依据。
常见级别详解
从低到高,日志级别依次为:
| 级别 | 说明 | 典型场景 |
|---|---|---|
| TRACE | 最细粒度的追踪信息,通常用于开发阶段的详细调试,生产环境极少开启 | 方法入口/出口参数追踪 |
| DEBUG | 调试信息,记录程序运行过程中的关键变量、方法调用等,便于开发人员排查问题 | 变量值变化、SQL 语句打印 |
| INFO | 重要运行信息,如服务启动、用户登录、请求处理完成等。生产环境默认开启 | 服务启动完成、用户操作记录 |
| WARN | 警告信息,表示程序运行中出现了潜在问题或非预期情况,但不会影响系统正常运行 | 配置项缺失使用默认值、接口响应时间过长 |
| ERROR | 错误信息,表示发生了影响功能正常执行的错误,需要开发人员关注和处理 | 数据库连接失败、第三方服务调用异常 |
| FATAL | 致命错误,表示发生了严重故障,导致应用程序无法继续运行 | 内存溢出、核心配置加载失败 |
级别过滤机制
日志框架通过设置根日志级别 来控制输出:只会输出大于等于当前设置级别的日志。
Spring Boot 默认的日志级别是 INFO ,意味着默认只输出 INFO 及以上 的日志,所以 TRACE 和 DEBUG 被过滤掉了。
java
@RequestMapping("/log")
@RestController
public class LogController {
private final static Logger logger = LoggerFactory.getLogger(LogController.class);
@RequestMapping("/print")
public String print(){
logger.info("logger 打印日志");
logger.trace("logger trace...");
logger.debug("logger debug...");
logger.info("logger info...");
logger.warn("logger warn...");
logger.error("logger error...");
return "打印日志";
}
}

在 application.properties 中添加一行来降低日志级别:
properties
logging.level.org.example.logdemo.controller=TRACE
或者针对整个项目的包:
properties
logging.level.org.example.logdemo=DEBUG
如果项目使用的是 application.yml 配置文件,对应的配置如下:
yml
logging:
level:
org:
example:
logdemo:
controller: TRACE
或者使用更简洁的包路径写法:
yml
logging:
level:
org.example.logdemo.controller: TRACE
针对整个项目包:
yml
logging:
level:
org.example.logdemo: DEBUG
不同环境的级别建议
| 环境 | 推荐级别 | 说明 |
|---|---|---|
| 开发环境 | DEBUG 或 TRACE |
输出尽可能多的信息,便于调试 |
| 测试环境 | DEBUG |
兼顾信息量和性能 |
| 生产环境 | INFO |
只记录重要信息和错误,避免日志过多影响性能 |
| 线上紧急排查 | 临时调为 DEBUG |
针对特定包或类开启,问题修复后恢复 |
3. 线程信息
记录产生该日志的线程名称或 ID。
- 格式示例 :
[main]、[http-nio-8080-exec-1] - 作用:在多线程应用中,帮助区分不同线程的执行路径,便于排查并发问题。
4. 日志记录器名称
通常是产生日志的类名或包名。
- 格式示例 :
com.example.service.UserService - 作用:快速定位日志来源,知道是哪段代码输出的日志。
5. 日志消息
日志的核心内容,描述具体发生了什么事件。
- 内容 :可以是简单的字符串,也可以是包含占位符的动态消息(如
用户 {} 登录成功)。 - 作用:提供问题或事件的详细描述。
6. 异常堆栈(可选)
当记录 ERROR 级别日志时,通常会附带异常堆栈信息。
- 格式:以换行缩进形式展示异常类型、消息及调用链。
- 作用:帮助开发者快速定位代码中抛出异常的具体位置和调用关系。
日志持久化
日志持久化是指将运行中的日志信息写入到文件或外部存储系统中,以便后续的排查、审计和监控。Spring Boot 提供了简洁的配置方式来实现日志的文件输出。
日志持久化有两种配置方式:
- 配置日志文件名 :通过
logging.file.name指定日志文件的完整路径和名称。 - 配置日志存储目录 :通过
logging.file.path指定日志文件的存放目录,文件名默认为spring.log。
优先级说明 :如果两个配置同时存在,以
logging.file.name为准。
yml
logging:
file:
# path: logger/ # 方式一:仅指定目录,文件名默认为 spring.log
name: logger/log.log # 方式二:指定完整文件名(优先级更高)
- 相对路径 :
logger/log.log表示在当前项目根目录下创建logger文件夹,日志写入log.log文件。 - 绝对路径 :
/var/log/myapp/app.log表示写入系统指定路径。

日志滚动策略
生产环境中,日志文件会持续增长,如果不加以控制,可能占满磁盘空间。因此需要配置日志滚动策略,当日志文件达到指定大小时自动归档。
yml
logging:
file:
name: logger/log.log
logback:
rollingpolicy:
max-file-size: 1KB # 单个日志文件最大 1KB
file-name-pattern: ${LOG_FILE}.%d{yyyy-MM-dd}.%i # 归档文件名格式
参数说明:
| 参数 | 说明 | 示例值 |
|---|---|---|
max-file-size |
单个日志文件的最大大小,超过后自动滚动 | 10MB、100MB |
file-name-pattern |
归档文件的命名规则 | ${LOG_FILE}.%d{yyyy-MM-dd}.%i |
max-history |
保留的历史归档文件数量(可选) | 7(保留最近 7 天) |
total-size-cap |
所有归档文件的总大小上限(可选) | 1GB |
归档文件名示例:
log.log.2026-05-24.0(当天第一个归档)log.log.2026-05-24.1(当天第二个归档)log.log.2026-05-23.0(前一天归档)
运行结果 :

日志框架
在 Java 开发中,日志框架是项目不可或缺的基础设施。一个优秀的日志框架能够帮助开发者高效地记录、管理和分析系统运行信息。目前主流的 Java 日志体系分为日志门面 和日志实现两部分。

日志门面
日志门面(Facade)提供了一套统一的日志记录 API,让开发者无需关心底层具体的日志实现。当需要切换日志框架时,只需更换底层实现,而无需修改业务代码。
| 门面框架 | 说明 |
|---|---|
| SLF4J(Simple Logging Facade for Java) | 目前最流行的日志门面,提供简洁的占位符 {} 格式化,性能优于字符串拼接 |
| Apache Commons Logging(JCL) | 早期的日志门面,Spring 框架默认使用,但存在类加载器问题 |
推荐 :新项目建议直接使用 SLF4J,它已成为 Java 日志领域的事实标准。
日志实现
日志实现是真正执行日志输出、格式化、存储等工作的底层框架。
| 实现框架 | 说明 |
|---|---|
| Logback | SLF4J 的原生实现,性能优异,功能强大,Spring Boot 默认使用 |
| Log4j2 | Apache 推出的高性能日志框架,支持异步日志,性能比 Logback 更高 |
| JUL(java.util.logging) | JDK 自带的日志实现,功能较弱,一般不直接使用 |
日志门面与实现的关系
#mermaid-svg-ZlENaKjpuMcyqcby{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZlENaKjpuMcyqcby .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZlENaKjpuMcyqcby .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZlENaKjpuMcyqcby .error-icon{fill:#552222;}#mermaid-svg-ZlENaKjpuMcyqcby .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZlENaKjpuMcyqcby .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZlENaKjpuMcyqcby .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZlENaKjpuMcyqcby .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZlENaKjpuMcyqcby .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZlENaKjpuMcyqcby .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZlENaKjpuMcyqcby .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZlENaKjpuMcyqcby .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZlENaKjpuMcyqcby .marker.cross{stroke:#333333;}#mermaid-svg-ZlENaKjpuMcyqcby svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZlENaKjpuMcyqcby p{margin:0;}#mermaid-svg-ZlENaKjpuMcyqcby .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZlENaKjpuMcyqcby .cluster-label text{fill:#333;}#mermaid-svg-ZlENaKjpuMcyqcby .cluster-label span{color:#333;}#mermaid-svg-ZlENaKjpuMcyqcby .cluster-label span p{background-color:transparent;}#mermaid-svg-ZlENaKjpuMcyqcby .label text,#mermaid-svg-ZlENaKjpuMcyqcby span{fill:#333;color:#333;}#mermaid-svg-ZlENaKjpuMcyqcby .node rect,#mermaid-svg-ZlENaKjpuMcyqcby .node circle,#mermaid-svg-ZlENaKjpuMcyqcby .node ellipse,#mermaid-svg-ZlENaKjpuMcyqcby .node polygon,#mermaid-svg-ZlENaKjpuMcyqcby .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZlENaKjpuMcyqcby .rough-node .label text,#mermaid-svg-ZlENaKjpuMcyqcby .node .label text,#mermaid-svg-ZlENaKjpuMcyqcby .image-shape .label,#mermaid-svg-ZlENaKjpuMcyqcby .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZlENaKjpuMcyqcby .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZlENaKjpuMcyqcby .rough-node .label,#mermaid-svg-ZlENaKjpuMcyqcby .node .label,#mermaid-svg-ZlENaKjpuMcyqcby .image-shape .label,#mermaid-svg-ZlENaKjpuMcyqcby .icon-shape .label{text-align:center;}#mermaid-svg-ZlENaKjpuMcyqcby .node.clickable{cursor:pointer;}#mermaid-svg-ZlENaKjpuMcyqcby .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZlENaKjpuMcyqcby .arrowheadPath{fill:#333333;}#mermaid-svg-ZlENaKjpuMcyqcby .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZlENaKjpuMcyqcby .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZlENaKjpuMcyqcby .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZlENaKjpuMcyqcby .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZlENaKjpuMcyqcby .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZlENaKjpuMcyqcby .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZlENaKjpuMcyqcby .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZlENaKjpuMcyqcby .cluster text{fill:#333;}#mermaid-svg-ZlENaKjpuMcyqcby .cluster span{color:#333;}#mermaid-svg-ZlENaKjpuMcyqcby div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZlENaKjpuMcyqcby .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZlENaKjpuMcyqcby rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZlENaKjpuMcyqcby .icon-shape,#mermaid-svg-ZlENaKjpuMcyqcby .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZlENaKjpuMcyqcby .icon-shape p,#mermaid-svg-ZlENaKjpuMcyqcby .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZlENaKjpuMcyqcby .icon-shape .label rect,#mermaid-svg-ZlENaKjpuMcyqcby .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZlENaKjpuMcyqcby .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZlENaKjpuMcyqcby .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZlENaKjpuMcyqcby :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 应用程序代码
SLF4J 门面 API
Logback
Log4j2
JUL
日志输出
注解输出日志:@Slf4j⭐
java
@RequestMapping("/log")
@RestController
public class LogController {
private final static Logger logger = LoggerFactory.getLogger(LogController.class);
@RequestMapping("/print")
public String print(){
logger.info("logger 打印日志");
logger.trace("logger trace...");
logger.debug("logger debug...");
logger.info("logger info...");
logger.warn("logger warn...");
logger.error("logger error...");
return "打印日志";
}
}
java
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RequestMapping("/log")
@RestController
public class LogController {
@RequestMapping("/print")
public String print(){
log.info("logger 打印日志");
log.trace("logger trace...");
log.debug("logger debug...");
log.info("logger info...");
log.warn("logger warn...");
log.error("logger error...");
return "打印日志";
}
}
使用 @Slf4j 注解后,代码发生了以下变化:
| 变化点 | 使用前 | 使用后 |
|---|---|---|
| 导入语句 | 需手动导入 org.slf4j.Logger 和 org.slf4j.LoggerFactory |
只需导入 lombok.extern.slf4j.Slf4j |
| 类注解 | 无 | 添加 @Slf4j 注解 |
| Logger 声明 | 手动声明 private final static Logger logger = LoggerFactory.getLogger(LogController.class); |
由 Lombok 自动生成,无需手动编写 |
| 变量名 | logger |
log(Lombok 自动生成的变量名为 log) |
| 代码简洁度 | 每个类都需要重复编写 Logger 声明代码 | 一行注解搞定,代码更简洁 |
核心变化 :
@Slf4j在编译时自动生成private static final Logger log = LoggerFactory.getLogger(当前类.class);,省去了手动声明 Logger 的样板代码,让开发者专注于业务逻辑。
为什么使用 SLF4J + Logback?
- 解耦:代码只依赖 SLF4J API,底层实现可随时切换。
- 性能:Logback 经过充分优化,性能优于 Log4j 1.x。
- 自动配置:Spring Boot 默认集成 SLF4J + Logback,开箱即用。
- 占位符支持 :SLF4J 的
{}占位符在参数较多时性能优于字符串拼接。