Spring Boot 日志系统详解

Spring Boot 日志系统详解

观看老杜的SpringBoot整理的一篇文章,些许糟粕,敬请斧正。
原视频链接_老杜springboot视频

一、日志概述

什么是日志?

日志是软件开发中用于记录系统运行时状态、事件和错误信息的关键技术手段。通过日志可以:

  • 追踪应用程序执行流程
  • 诊断和排查问题
  • 监控系统运行状态
  • 分析用户行为
  • 满足审计需求


二、Java 日志框架体系

1. 抽象的日志门面(Facade)

日志门面提供统一的日志API,允许应用程序与具体日志实现解耦:

日志门面说明
SLF4JSimple Logging Facade for Java,目前最主流的日志门面
JCL (Jakarta Commons Logging)Apache 的日志门面,逐渐被 SLF4J 取代
JBoss LoggingJBoss 系列产品使用的日志门面

2. 具体的日志实现

这些是实际的日志记录工具:

日志实现特点
LogbackSLF4J 的原生实现,Spring Boot 默认使用
Log4j2Apache 的高性能日志框架,支持异步日志和丰富插件
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
   |      |      |      |       |       |
   |      |      |      |       |        → 系统即将崩溃
   |      |      |      |        → 需要立即处理
   |      |      |       → 需要注意
   |      |       → 正常业务消息
   |       → 调试信息
    → 最详细跟踪
最佳实践建议
  1. 生产环境推荐设置
    • 常规运行: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.namelogging.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>
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值