Spring Boot 日志系统详解
观看老杜的SpringBoot整理的一篇文章,些许糟粕,敬请斧正。
原视频链接_老杜springboot视频
一、日志概述
什么是日志?
日志是软件开发中用于记录系统运行时状态、事件和错误信息的关键技术手段。通过日志可以:
- 追踪应用程序执行流程
- 诊断和排查问题
- 监控系统运行状态
- 分析用户行为
- 满足审计需求
二、Java 日志框架体系
1. 抽象的日志门面(Facade)
日志门面提供统一的日志API,允许应用程序与具体日志实现解耦:
| 日志门面 | 说明 |
|---|---|
| SLF4J | Simple Logging Facade for Java,目前最主流的日志门面 |
| JCL (Jakarta Commons Logging) | Apache 的日志门面,逐渐被 SLF4J 取代 |
| JBoss Logging | JBoss 系列产品使用的日志门面 |
2. 具体的日志实现
这些是实际的日志记录工具:
| 日志实现 | 特点 |
|---|---|
| Logback | SLF4J 的原生实现,Spring Boot 默认使用 |
| Log4j2 | Apache 的高性能日志框架,支持异步日志和丰富插件 |
| JUL (java.util.logging) | JDK 自带的日志工具,功能相对简单 |
| Log4j (1.x) | 已淘汰,存在严重漏洞 |
三、日志级别概述
日志级别控制
Spring Boot 支持以下日志级别(从低到高):
- TRACE
- DEBUG
- INFO (Spring Boot 默认级别)
- WARN
- ERROR
- FATAL
1. TRACE(追踪)
-
级别值:最低的日志级别
-
使用场景:
- 记录最详细的运行时信息
- 开发阶段跟踪程序执行流程
- 排查复杂问题时需要查看的细粒度信息
-
特点:
- 会产生大量日志输出
- 生产环境通常关闭
2. DEBUG(调试)
-
级别值:比 TRACE 高一级
-
使用场景:
- 开发调试期间使用
- 记录有助于诊断问题的详细信息
- 记录关键变量值、方法入参/返回值
-
特点:
- 生产环境通常关闭或按需开启
- 比 TRACE 更精简但仍较详细
3. INFO(信息)
-
级别值:Spring Boot 默认级别
-
使用场景:
- 记录应用程序运行时的重大事件
- 业务逻辑的关键节点记录
- 系统启动/关闭等重要操作
-
特点:
- 生产环境常规运行时应保持开启
- 信息量适中,不会过多也不会过少
4. WARN(警告)
-
级别值:比 INFO 更高
-
使用场景:
- 记录潜在问题或异常情况
- 不影响系统继续运行但需要关注的问题
- 非预期但已处理的异常情况
-
特点:
- 需要人工关注但无需立即处理
- 可能指示未来会出现的问题
5. ERROR(错误)
-
级别值:高优先级
-
使用场景:
- 记录错误和异常情况
- 业务逻辑处理失败
- 需要立即关注的问题
-
特点:
- 系统仍能运行但功能可能受限
- 通常需要人工干预
-
示例:
6. FATAL(致命)
-
级别值:最高级别(注意:Logback/SLF4J 实际上没有 FATAL 级别,等同于 ERROR)
-
使用场景:
- 记录导致应用程序崩溃的致命错误
- 系统无法继续运行的严重故障
-
特点:
- 在 Log4j 中存在,但 SLF4J/Logback 中用 ERROR 代替
- 发生后通常需要重启服务
各级别关系图示
严重程度低 → 高
TRACE → DEBUG → INFO → WARN → ERROR → FATAL
| | | | | |
| | | | | → 系统即将崩溃
| | | | → 需要立即处理
| | | → 需要注意
| | → 正常业务消息
| → 调试信息
→ 最详细跟踪
最佳实践建议
- 生产环境推荐设置:
- 常规运行:INFO
- 问题排查:可临时调整为 DEBUG
# 单个Logger
java -jar app.jar --logging.level.com.example=DEBUG
# 多个Logger
java -jar app.jar \
--logging.level.root=WARN \
--logging.level.com.example.service=DEBUG
四、Spring Boot 日志系统
1. 默认日志配置
spring-boot-starter:3
|——->org.springframework.boot:spring-boot-starter-logging
|——————>logback-classic
|——————>log4j-to-slf4j
|——————>jul-to-slf4j
Spring Boot 默认使用 SLF4J + Logback 组合:
- 无需额外配置即可使用
- 提供INFO的默认配置
- 支持通过
application.properties/yml调整
2. 日志粗细粒度:
# 设置root日志级别
logging.level.root=WARN
# 设置特定包日志级别
logging.level.org.springframework.web=DEBUG
logging.level.com.myapp=INFO
配置优先级
Spring Boot 的日志级别遵循 “就近原则”(更具体的配置会覆盖更通用的配置):
-
特定包配置(如
org.springframework.web)> root 配置 -
当某个类/包有专属配置时,使用专属配置
-
没有专属配置的类/包,则继承
root的配置
debug=true
# Spring Boot 内部日志(org.springframework 包)设置
# info=true
# error-true
# ...
debug=true
-
当设置
debug=true时,本质上就是将org.springframework包下的日志级别设为DEBUG(但不会影响其他包的日志级别) -
如果 同时 通过
logging.level显式配置了某些包的日志级别,这些手动配置会 覆盖debug=true的默认行为
想看到Mybatis查询时的 “SQL日志”
# 设置root日志级别
logging.level.root=DEBUG
# 或者指定mapper包下的日志级别为debug
logging.level.com.xxx.mapper=debug
生成的日志示例
2025-05-12T08:45:18.751+08:00 INFO 7336 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2025-05-12T08:45:28.441+08:00 INFO 7336 --- [nio-8080-exec-1] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@67dcc564
2025-05-12T08:45:28.443+08:00 INFO 7336 --- [nio-8080-exec-1] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2025-05-12T08:45:28.450+08:00 DEBUG 7336 --- [nio-8080-exec-1] c.e.mapper.VipMapper.selectAll_COUNT : ==> Preparing: SELECT count(0) FROM vip
2025-05-12T08:45:28.465+08:00 DEBUG 7336 --- [nio-8080-exec-1] c.e.mapper.VipMapper.selectAll_COUNT : ==> Parameters:
2025-05-12T08:45:28.517+08:00 DEBUG 7336 --- [nio-8080-exec-1] c.e.mapper.VipMapper.selectAll_COUNT : <== Total: 1
2025-05-12T08:45:28.521+08:00 DEBUG 7336 --- [nio-8080-exec-1] com.example.mapper.VipMapper.selectAll : ==> Preparing: select vip.id as vip_id, vip.`name` as `vip_name`, vip.card_number as vip_card_number, vip.birth as vip_birth from vip LIMIT ?, ?
2025-05-12T08:45:28.522+08:00 DEBUG 7336 --- [nio-8080-exec-1] com.example.mapper.VipMapper.selectAll : ==> Parameters: 2(Long), 2(Integer)
2025-05-12T08:45:28.564+08:00 DEBUG 7336 --- [nio-8080-exec-1] com.example.mapper.VipMapper.selectAll : <== Total: 2
2025-05-12T11:41:51.395+08:00 INFO 7336 --- [ionShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
2025-05-12T11:41:51.690+08:00 INFO 7336 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete
2025-05-12T11:41:51.700+08:00 INFO 7336 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2025-05-12T11:42:01.720+08:00 WARN 7336 --- [ionShutdownHook] com.zaxxer.hikari.pool.HikariPool : Timed-out waiting for close connection executor to shutdown
2025-05-12T11:42:01.720+08:00 INFO 7336 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
3. 日志输出到文件
基础文件日志配置
在 application.properties/yml 中配置:
# 输出到指定文件(默认追加)
logging.file.name=app.log
# 或者输出到目录(生成 spring.log)
# logging.file.path=/var/log/myapp
# logging.file.path=./logs
logging.file.name和logging.file.path同时存在时,只会生效logging.file.name
# 内部控制台输出格式
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%thread] %highlight(%-5level) %cyan(%logger{36}) - %msg%n
# 输出示例:
# 2025-05-01 14:30:00.123 [http-nio-8080-exec-1] INFO com.example.MyController - Request received
# 日志内部文件输出格式
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %highlight(%-5level) %cyan(%logger{36}) - %msg%n
# 输出示例:
# 2025-05-01 14:30:00.123 [http-nio-8080-exec-1] INFO com.example.MyController - Request received
格式占位符详解
| 占位符 | 作用 | 示例输出 |
|---|---|---|
%d{pattern} | 日期时间(支持 SimpleDateFormat 格式) | 2025-05-01 14:30:00 |
%thread | 线程名 | http-nio-8080-exec-1 |
%-5level | 日志级别(左对齐,固定宽度5) | INFO , ERROR |
%logger{length} | 日志记录器名称({length}限制显示长度) | c.e.MyController |
%msg | 日志消息内容 | User login success |
%n | 换行符 | - |
%highlight() | 彩色输出(仅控制台生效,需终端支持) | 红色 ERROR,绿色 INFO |
%cyan() | 设置颜色(其他颜色:%red, %green, %yellow, %blue, %magenta, %white) | 青色文本 |
滚动策略(默认Logback配置)
# 日志文件最大大小(默认10MB)
logging.logback.rollingpolicy.max-file-size=50MB
# 保留的日志文件天数(默认7)
logging.logback.rollingpolicy.max-history=30
# 日志文件总大小限制(默认0-无限制)
logging.logback.rollingpolicy.total-size-cap=1GB
# 归档日志文件名格式
logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}-%d{yyyy-MM-dd}.%i.gz
# 解释:
# ${LOG_FILE} - 文件名称 由上述的 logging.file.path就是(spring)logging.file.name就是(name)
# %d{yyyy-MM-dd} - 日期格式(触发滚动的日期)
# %i - 索引号(同一天内按大小滚动时递增)
# .gz - 压缩归档
生成的文件示例:
app-2025-05-01.0.gz
app-2025-05-01.1.gz # 同一天超过50MB后生成
app-2025-05-02.0.gz # 新日期
4. 日志框架切换
一般不推荐切换日志框架,普通项目logback就够用了,不需要折腾。
切换到 Log4j2
步骤 1:排除默认的 Logback
修改 pom.xml
<!-- pom.xml -->
<dependencies>
<!-- 排除 spring-boot-starter-web 中的 logback -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加 log4j2 支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
</dependencies>
步骤 2:添加 Log4j2 配置文件
创建 src/main/resources/log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!--
Log4j2 配置文件
status="WARN" : 设置Log4j2内部日志级别为WARN,避免过多框架自身日志输出
-->
<Configuration status="WARN">
<!-- 定义所有输出器(Appender) -->
<Appenders>
<!-- 1. 控制台输出器 -->
<Console name="Console" target="SYSTEM_OUT">
<!--
输出格式:
%d{yyyy-MM-dd HH:mm:ss.SSS} - 日期时间(精确到毫秒)
[%t] - 线程名(用方括号包裹)
%-5level - 日志级别(左对齐,固定宽度5字符)
%logger{36} - 日志记录器名称(最长36字符,超长部分缩写)
%msg - 实际日志消息
%n - 换行符
-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<!-- 2. 滚动文件输出器 -->
<RollingFile name="File"
fileName="logs/app.log" <!-- 当前活动日志文件路径 -->
filePattern="logs/app-%d{yyyy-MM-dd}-%i.log"> <!-- 归档文件命名模式 -->
<!-- 使用与控制台相同的格式 -->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<!-- 滚动触发策略 -->
<Policies>
<!--
基于时间的滚动策略:
interval="1" - 每天滚动一次(单位:天)
modulate="true" - 在整点时间滚动(如午夜00:00)
-->
<TimeBasedTriggeringPolicy interval="1" modulate="true"/>
<!--
基于大小的滚动策略:
size="50 MB" - 当日志文件达到50MB时触发滚动
(与时间策略结合:同一天内超过50MB会生成带索引的新文件)
-->
<SizeBasedTriggeringPolicy size="50 MB"/>
</Policies>
<!--
滚动覆盖策略:
max="30" - 最多保留30个归档文件(超出时删除最旧文件)
不设置totalSizeCap时,仅根据文件数量清理
-->
<DefaultRolloverStrategy max="30"/>
</RollingFile>
</Appenders>
<!-- 定义日志记录器(Logger) -->
<Loggers>
<!--
根日志记录器:
level="info" - 默认日志级别为INFO
所有日志将同时输出到Console和File两个Appender
-->
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
<!--
可在此添加特定包/类的特殊日志配置,例如:
<Logger name="org.springframework" level="warn"/>
<Logger name="com.myapp" level="debug" additivity="false">
<AppenderRef ref="File"/>
</Logger>
-->
</Loggers>
</Configuration>
------------------------------------------------------可选:启用异步日志(性能优化)------------------------------------------------------
Log4j2 提供两种异步机制,推荐 AsyncLogger(全异步) 方案:
方案对比
| 方案 | 性能 | 可靠性 | 适用场景 |
|---|---|---|---|
| Async Appender | 中等 | 较高 | 部分日志异步 |
| AsyncLogger | 极高 | 依赖配置 | 全量日志异步(推荐) |
步骤 1:添加 Disruptor 依赖:
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.4</version>
</dependency>
步骤 2:修改log4j2.xml 文件:
修改src/main/resources/log4j2.xml 用全局异步模式
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<!-- 启用全异步模式(全局) -->
<AsyncLoggerConfig rootLevel="info" includeLocation="false">
<AsyncLogger>
...
</AsyncLogger>
<Loggers>
...
</Loggers>
</AsyncLoggerConfig>
</Configuration>
关键参数说明
includeLocation="false":禁用行号记录(提升30%性能)blocking="false":非阻塞模式(需足够环形队列容量)waitStrategy="Timeout":平衡CPU和延迟
或选用部分异步模式
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<!-- 启用异步模式(局部) -->
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd}-%i.log">
<!-- 同步输出器配置 -->
</RollingFile>
</Appenders>
<Loggers>
<!-- 同步记录重要日志 -->
<Logger name="com.myapp.service" level="info" additivity="false">
<AppenderRef ref="RollingFile"/>
</Logger>
<!-- 异步记录DEBUG日志 -->
<AsyncLogger name="com.myapp.debug" level="debug">
<AppenderRef ref="RollingFile"/>
<!-- 队列参数 -->
<RingBufferSize>256 * 1024</RingBufferSize> <!-- 默认256K -->
<ThreadPriority>5</ThreadPriority>
</AsyncLogger>
</Loggers>
</Configuration>
385

被折叠的 条评论
为什么被折叠?



