SpringBoot教程(十九) | SpringBoot集成Slf4j日志门面(优化版)
SpringBoot教程(十九) | SpringBoot集成Slf4j日志门面
- 一、概述
- 二、前言
- 三、SLF4J日志门面核心认知
- 四、依赖说明:开箱即用,无需额外引入
- 4.1 核心依赖传递关系
- 4.2 可选依赖:Lombok简化日志对象创建
- 五、Logback的配置文件(一般都需配置)
- 情况一:不配置任何关于logback的配置文件
- 情况二:配置关于logback的配置文件
- 六、具体配置文件
- 6.1 开发环境建议配置
- 6.2 生产环境建议配置
- 6.3 变量抽取操作(可选)
- 七、日志使用实战:两种常用方式
- 7.1 方式1:不使用@Slf4j注解(无依赖)
- 7.2 方式2:使用@Slf4j注解(简化代码)
- 7.2.2 代码使用示例
一、概述
对于一个Web项目来说,日志框架是必不可少的,日志的记录可以帮助我们在开发以及维护过程中快速定位错误。
SLF4J、Log4j、Logback、JDK Logging等都是常见的日志框架,
本文核心介绍SpringBoot整合“SLF4J(日志门面)+Logback(日志实现)”的操作。
二、前言
从Spring Boot 1.x版本开始,它就默认集成了Logback作为日志实现框架,搭配SLF4J作为日志门面,这一默认配置在后续版本中持续保持。
尽管Spring Boot支持切换为Log4j2等其他日志框架,但“SLF4J+Logback”组合因性能优异、配置灵活且无需额外依赖,成为大多数项目的首选。
本文也将围绕这一默认组合展开。
三、SLF4J日志门面核心认知
在集成配置前,需先明确SLF4J的核心定位——它并非日志实现,而是一套日志门面(接口规范),旨在解决“不同日志框架切换时修改业务代码”的痛点。
-
SLF4J的作用:定义统一的日志接口(如
log.info()
、log.error()
),屏蔽底层日志实现(Logback、Log4j2等)的差异。若后续需从Logback切换为Log4j2,仅需替换依赖和配置文件,业务代码无需改动。 -
与Logback的关系:Logback是SLF4J的“原生实现”,性能优于传统Log4j,且是SpringBoot默认集成方案——引入
spring-boot-starter
或spring-boot-starter-web
时,会自动加载SLF4J+Logback的依赖,无需额外引入。 -
核心优势:支持参数化日志(如
log.info("用户{}操作成功", userId)
)避免字符串拼接性能损耗,同时兼容主流日志框架,是企业级开发的标准选型。
SLF4J的参数化日志特性需重点关注:传统字符串拼接(如"用户"+userId+"操作成功"
)在日志级别未启用时仍会产生拼接开销,而log.info("用户{}操作成功", userId)
会先判断日志级别,未启用时直接跳过参数处理,提升性能。
四、依赖说明:开箱即用,无需额外引入
Spring Boot的“开箱即用”理念在日志框架中体现得淋漓尽致,只要引入核心启动器,就会自动集成SLF4J和Logback,无需手动添加日志相关依赖。
4.1 核心依赖传递关系
-
spring-boot-starter
:核心启动器,内置SLF4J核心接口和Logback实现依赖,提供基础日志功能; -
spring-boot-starter-web
:Web项目启动器,内部依赖spring-boot-starter
,因此也间接包含日志依赖,Web项目无需额外配置。
<!-- 非Web项目只需引入核心启动器 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency><!-- Web项目引入Web启动器即可 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
4.2 可选依赖:Lombok简化日志对象创建
若想使用@Slf4j
注解自动生成日志对象(避免手动写LoggerFactory.getLogger()
),需额外引入Lombok依赖,注意scope=provided
表示编译时生效,打包时不引入Lombok库(生成的代码已包含在类文件中)。
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version> <!-- 版本可根据项目需求调整 --><scope>provided</scope>
</dependency>
五、Logback的配置文件(一般都需配置)
Spring Boot 会自动从类路径(classpath)中查找 logback-spring.xml、logback-classic.xml、logback.groovy 和 logback.xml 文件(按照顺序),并使用它们作为 Logback 的配置。
情况一:不配置任何关于logback的配置文件
- 默认日志级别:Spring Boot的默认日志级别为INFO
- 日志格式:Spring Boot在控制台上的默认日志输出格式可能因版本而异,但通常包含时间戳、日志级别、线程名称、日志输出者的名称(通常是类名或文件名)以及日志消息本身。
- 默认文件输出:如果不进行任何配置,Spring Boot通常不会将日志输出到文件中,而是仅输出到控制台
情况二:配置关于logback的配置文件
- 文件名:命名为
logback-spring.xml
(在SpringBoot项目中一般情况下以这个命名)- 位置:把logback-spring.xml 文件放到
src/main/resources
目录下
( Spring Boot 会在启动时自动加载这个文件,而无需你在 application.yml 或 application.properties 中进行任何配置)- 如果你是想自定义这个xml的名称 或者 自定义路径
可以通过logging.config属性配置
例如:logging.config=classpath:logging-config.xml 去操作
日志级别用于控制日志输出的详细程度,logback遵循通用日志级别规范,按严重程度从低到高依次划分,不同级别对应不同的使用场景:
日志常用的六个级别,根据严重程度由低到高,依次为:trace(追踪)<debug(调试 ) < info(消息) < warn(警告) < error(错误) < fatal(严重错误)。
“级别越小” = “门槛越低”,能进来的日志就越多(越详细)
通常可以根据实际所需要的颗粒度的大小选择其中的几个,当前常用debug,info,warn,error4个级别。一般都是配置的info级别
注意:记住,Logback 的配置本身并不直接支持将 System.out 和 System.err 的输出重定向到日志文件中的哦
六、具体配置文件
6.1 开发环境建议配置
<?xml version="1.0" encoding="UTF-8"?>
<!-- 【Spring开发环境】Logback配置:控制台同步(实时)+ 文件异步(高性能)核心特性:控制台实时输出、文件异步写入、彩色高亮、时间+大小双切割、traceId追踪
-->
<!-- debug="false":关闭Logback自身调试日志,避免干扰业务日志 -->
<!-- scan="true" + scanPeriod="30 seconds":配置修改后30秒内自动生效,无需重启应用 -->
<configuration debug="false"scan="true"scanPeriod="30 seconds"><!-- 彩色日志支持(Spring内置) --><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /><!-- 1. 控制台输出器(同步,保证实时性和顺序性) --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!-- 控制台格式:彩色+线程+类名+行号+traceId,直观调试 --><pattern>%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr([%-10.10thread]){faint} %clr(%-5level) %clr(%-50.50logger{50}:%-3L){cyan} %clr(%X{traceId:-}){magenta} %clr(-){faint} %msg%n</pattern></encoder></appender><!-- 2. 文件输出器(同步基础组件,被异步包装) --><appender name="FILE_SYNC" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 当前日志文件路径 --><file>logs/dev-spring-app.log</file><!-- 时间+大小双切割策略 --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>logs/dev-spring-app.%d{yyyy-MM-dd-HH}.log</fileNamePattern><maxHistory>24</maxHistory> <!-- 保留24小时日志 --><!-- 单文件超过100MB时提前切割 --><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>100MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!-- 文件格式:包含完整信息+traceId,便于追溯 --><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %X{traceId:-} %-5level %logger{50}:%L - %msg%n</pattern></encoder></appender><!-- 3. 文件异步输出器(包装同步文件输出,避免IO阻塞) --><appender name="FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="FILE_SYNC" /> <!-- 仅异步处理文件日志 --><queueSize>1024</queueSize> <!-- 日志队列容量(开发环境足够) --><discardingThreshold>819</discardingThreshold> <!-- 队列80%满时,丢弃DEBUG及以下日志 --><includeMdcKeyName>traceId</includeMdcKeyName> <!-- 保留MDC中的traceId --><neverBlock>false</neverBlock> <!-- ERROR级日志不丢失(队列满时阻塞等待) --></appender><!-- 自定义日志级别(【必须替换】为你的项目基础包名,如com.xxx.api) --><logger name="com.yourproject" level="DEBUG" additivity="false"><appender-ref ref="CONSOLE"/> <!-- 控制台同步输出 --><appender-ref ref="FILE_ASYNC"/> <!-- 文件异步输出 --></logger><!-- 第三方框架日志控级(开发环境常用配置) --><logger name="org.springframework" level="INFO"/> <!-- 屏蔽Spring内部DEBUG --><logger name="org.mybatis" level="DEBUG"/> <!-- 输出SQL及参数 --><logger name="com.baomidou.mybatisplus" level="DEBUG"/> <!-- MyBatis-Plus SQL输出 --><logger name="com.zaxxer.hikari" level="INFO"/> <!-- 连接池状态信息 --><logger name="org.springframework.web" level="INFO"/> <!-- 请求映射等核心信息 --><logger name="okhttp3" level="INFO"/> <!-- HTTP请求状态 --><!-- 根日志配置(未单独配置的类遵循此规则) --><root level="DEBUG"><appender-ref ref="CONSOLE"/> <!-- 控制台同步 --><appender-ref ref="FILE_ASYNC"/> <!-- 文件异步 --></root>
</configuration>
6.2 生产环境建议配置
<?xml version="1.0" encoding="UTF-8"?>
<!-- 生产环境 Logback 核心设计:1. 日志持久化到文件(按天+大小拆分,避免单文件过大)2. 区分 ERROR 级别日志(单独存储,便于快速定位错误)3. 异步输出(避免日志操作阻塞业务线程,提升性能)4. 严格控制日志级别(默认 INFO,禁用 DEBUG 避免冗余)5. 规范日志保留策略(防止磁盘占满)6. 关闭配置自动扫描(避免意外修改生效)7. 异步队列优化(降低高并发阻塞风险,不影响核心日志)8. 日志压缩(归档文件自动压缩,减少磁盘占用)9. 磁盘满应急处理(谨慎模式避免服务异常)10. 异步日志阻塞风险降低(队列满时丢弃老日志,优先保业务不阻塞)11. 分布式追踪字段(新增traceId/spanId,支持跨服务链路串联)
-->
<!-- debug="false" 关闭 Logback 自身调试日志,避免干扰生产日志 -->
<!-- scan="false" 生产环境禁用自动扫描:防止配置文件被意外修改后生效 -->
<configuration debug="false" scan="false"><!-- 1. 定义日志存储路径(建议通过环境变量注入,避免硬编码) --><!-- 生产环境需使用绝对路径,且确保应用有写入权限(如 /var/log/yourapp/ 或 D:/prod/logs/) --><property name="LOG_HOME" value="${LOG_PATH:-/var/log/yourapp}"/> <!-- 优先取环境变量 LOG_PATH,默认路径兜底 --><property name="MAX_HISTORY" value="30"/> <!-- 日志保留天数(30天,可根据磁盘大小调整) --><property name="MAX_FILE_SIZE" value="100MB"/> <!-- 单个日志文件最大大小(避免过大,便于传输和解析) --><!-- 2. 通用日志格式(无颜色,生产环境日志文件无需彩色) --><!-- 新增:添加traceId/spanId字段,适配分布式链路追踪(需配合SkyWalking/APM等工具使用) --><property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L [%X{traceId}] [%X{spanId}] - %msg%n"/><!-- 3. 普通日志文件输出(INFO 及以上级别,不含 ERROR) --><appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 磁盘满应急处理:谨慎模式(文件操作失败时不抛异常,避免服务受影响) --><prudent>true</prudent><!-- 过滤掉 ERROR 级别,只保留 INFO/WARN(与 ERROR 日志分离) --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>DENY</onMatch> <!-- 匹配 ERROR 级别则拒绝 --><onMismatch>ACCEPT</onMismatch> <!-- 不匹配则接受 --></filter><!-- 日志文件路径及命名规则 --><file>${LOG_HOME}/info.log</file> <!-- 当前日志文件 --><!-- 轮转策略:按时间(天)+ 大小拆分 + 自动压缩 --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 归档文件命名:info-2025-10-20.0.log.zip(每天一个文件夹,按大小拆分并压缩) --><fileNamePattern>${LOG_HOME}/info/%d{yyyy-MM-dd}/info.%i.log</fileNamePattern><maxHistory>${MAX_HISTORY}</maxHistory> <!-- 保留30天归档日志 --><compressionMode>ZIP</compressionMode> <!-- 归档日志自动压缩(ZIP格式,压缩率~10:1) --><!-- 结合大小限制:单个文件超过 100MB 则生成新文件(%i 递增) --><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>${MAX_FILE_SIZE}</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><!-- 日志格式编码 --><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${LOG_PATTERN}</pattern><charset>UTF-8</charset> <!-- 明确字符集,避免中文乱码 --></encoder></appender><!-- 4. 错误日志文件输出(仅 ERROR 级别,便于快速排查问题) --><appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"><!-- 磁盘满应急处理:谨慎模式(文件操作失败时不抛异常,避免服务受影响) --><prudent>true</prudent><!-- 只保留 ERROR 级别日志 --><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>ACCEPT</onMatch> <!-- 匹配 ERROR 则接受 --><onMismatch>DENY</onMismatch> <!-- 不匹配则拒绝 --></filter><!-- 错误日志文件路径 --><file>${LOG_HOME}/error.log</file> <!-- 当前错误日志文件 --><!-- 轮转策略(同普通日志,单独归档+压缩) --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_HOME}/error/%d{yyyy-MM-dd}/error.%i.log</fileNamePattern><maxHistory>${MAX_HISTORY}</maxHistory><compressionMode>ZIP</compressionMode> <!-- 归档日志自动压缩 --><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>${MAX_FILE_SIZE}</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${LOG_PATTERN}</pattern><charset>UTF-8</charset></encoder></appender><!-- 5. 异步输出(核心性能优化:避免日志写入阻塞业务线程) --><appender name="ASYNC_INFO" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="FILE_INFO"/> <!-- 异步转发到普通日志文件 --><queueSize>2048</queueSize> <!-- 增大缓冲区(原1024→2048),降低高并发下队列满的概率 --><!-- neverBlock改为true,队列满时不阻塞业务线程 --><neverBlock>true</neverBlock><!-- 配置溢出策略,队列满时丢弃最老日志(最多丢弃500条,平衡日志完整性与业务可用性) --><overflowPolicy class="ch.qos.logback.core.spi.DiscardingAsyncOverflowPolicy"><maxMessageCount>500</maxMessageCount></overflowPolicy><discardingThreshold>5</discardingThreshold> <!-- 队列满5%时丢弃DEBUG日志(生产禁用DEBUG,无实际影响) --></appender><appender name="ASYNC_ERROR" class="ch.qos.logback.classic.AsyncAppender"><appender-ref ref="FILE_ERROR"/> <!-- 异步转发到错误日志文件 --><queueSize>2048</queueSize> <!-- 同INFO队列优化 --><!-- 错误日志调整:neverBlock=false(队列满时短暂阻塞,优先保证错误日志不丢失)权衡说明:错误日志(如订单失败、接口报错)为故障排查关键证据,短暂阻塞业务线程换取日志完整性风险提示:高并发下若错误日志突增,可能导致业务线程短暂等待(建议通过监控告警及时处理错误源头) --><neverBlock>false</neverBlock><!-- 移除丢弃策略:错误日志不丢弃,队列满时通过阻塞等待缓冲(配合neverBlock=false生效) --><discardingThreshold>0</discardingThreshold> <!-- 0表示不丢弃任何级别日志(包括DEBUG,但生产已禁用DEBUG) --></appender><!-- 6. 日志级别控制(生产环境严格限制,减少冗余) --><!-- 6.1 自己项目的包:INFO 级别(禁用 DEBUG,避免日志量过大) --><logger name="com.yourproject" level="INFO" additivity="false"><appender-ref ref="ASYNC_INFO"/><appender-ref ref="ASYNC_ERROR"/></logger><!-- 6.2 第三方框架:按需调整,原则是“只输出必要日志” --><logger name="org.springframework" level="WARN"/> <!-- Spring 框架:WARN及以上(减少内部INFO日志) --><logger name="org.mybatis" level="WARN"/> <!-- MyBatis:WARN及以上(生产无需SQL调试日志) --><logger name="com.zaxxer.hikari" level="INFO"/> <!-- 连接池:INFO级看初始化/异常即可 --><logger name="okhttp3" level="WARN"/> <!-- HTTP客户端:整体WARN级别,减少非关键日志 --><!-- 精细化okhttp3日志:保留连接相关关键INFO日志(如连接超时、重试等,辅助排查网络问题) --><logger name="okhttp3.internal.connection" level="INFO"/><logger name="org.apache.http" level="WARN"/><!-- 7. 根日志配置(兜底:所有未单独配置的类) --><root level="INFO"> <!-- 根级别设为INFO(过滤DEBUG日志) --><appender-ref ref="ASYNC_INFO"/><appender-ref ref="ASYNC_ERROR"/></root></configuration>
6.3 变量抽取操作(可选)
如果你想要将logback.xml配置文件中的变量抽取到application.yml或application.properties中
可以 使用
springProperty
标签
例如:
<configuration> <!-- 定义属性,从application.yml或application.properties中读取 --> <springProperty scope="context" name="customLogLevel" source="logging.custom.level" defaultValue="INFO"/> <!-- 使用该属性设置日志级别 --> <logger name="com.example.myapp" level="${customLogLevel}"/> <!-- 其他配置... -->
</configuration>
application.yml 示例:
logging: custom: level: DEBUG
或者,如果你使用的是application.properties:
logging.custom.level=DEBUG
七、日志使用实战:两种常用方式
配置完成后,通过SLF4J接口输出日志,推荐两种方式:手动创建日志对象(无Lombok依赖)和@Slf4j
注解(简化代码)。
7.1 方式1:不使用@Slf4j注解(无依赖)
无需Lombok,通过LoggerFactory
手动获取日志对象,适用于不依赖Lombok的项目。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class LogTestController {// 手动创建Logger对象,参数为当前类的Class(便于定位日志来源)private static final Logger log = LoggerFactory.getLogger(LogTestController.class);@GetMapping("/test-log")public String testLog() {// 输出不同级别日志log.trace("这是TRACE级日志(最详细,默认不输出)");log.debug("这是DEBUG级日志(开发调试用)");log.info("这是INFO级日志(常规业务信息)");log.warn("这是WARN级日志(警告信息,如参数异常)");log.error("这是ERROR级日志(错误信息,含异常堆栈)", new RuntimeException("模拟异常"));return "日志输出完成";}
}
7.2 方式2:使用@Slf4j注解(简化代码)
需先引入“四、依赖说明”中4.2节的Lombok依赖,通过注解自动生成日志对象,减少重复代码。
7.2.2 代码使用示例
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@Slf4j // Lombok自动生成Logger对象,变量名固定为log
public class LogTestController {@GetMapping("/test-log-lombok")public String testLog() {// 直接使用log对象输出日志log.info("使用@Slf4j输出INFO日志");log.error("使用@Slf4j输出ERROR日志", new RuntimeException("模拟异常"));return "Lombok日志输出完成";}
}