一、为什么选择 logback?
logback 是由 log4j 创始人 ceki gülcü 开发的日志框架,是 slf4j 的原生实现。相比 log4j 和 jul,它有几个明显优势:
- 性能更高:内部实现经过优化,异步日志性能优于 log4j
- 配置更灵活:支持 xml 和 groovy 配置,条件化配置
- 自动重载:配置文件修改后自动重新加载,无需重启
- 自动压缩归档:日志文件滚动后自动压缩,无需额外配置
- 与 slf4j 无缝集成:slf4j 是日志门面标准,logback 是其原生实现
spring boot 默认就使用 logback 作为日志实现。如果引入的是 spring-boot-starter-web 或 spring-boot-starter,logback 已经被自动引入,不需要额外添加依赖。只有纯 spring 项目才需要手动引入。
二、依赖引入
2.1 spring boot 项目
spring boot 的 starter 已经包含了 logback,不需要手动引入:
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
<!-- 传递依赖中已包含 spring-boot-starter-logging,即 logback + slf4j -->
</dependency>可以查看依赖树确认:
mvn dependency:tree | grep logback
输出应包含:
ch.qos.logback:logback-classic ch.qos.logback:logback-core org.slf4j:slf4j-api
2.2 纯 spring 项目
手动引入 slf4j 和 logback:
<dependency>
<groupid>org.slf4j</groupid>
<artifactid>slf4j-api</artifactid>
<version>2.0.9</version>
</dependency>
<dependency>
<groupid>ch.qos.logback</groupid>
<artifactid>logback-classic</artifactid>
<version>1.4.11</version>
</dependency>注意:引入 logback 后,应排除其他日志实现(如 commons-logging、log4j),避免多个日志框架冲突。spring 的 spring-jcl 已经桥接了 commons-logging,不需要额外处理。
三、logback 配置文件
logback 会在 classpath 下按以下顺序查找配置文件:
logback-spring.xml(spring boot 推荐)logback-spring.groovylogback.xmllogback.groovy
logback.xml 与 logback-spring.xml 的区别:
logback.xml:由 logback 直接加载,早于 spring 容器启动,不支持 spring 的 profile 和属性注入logback-spring.xml:由 spring boot 加载,支持<springprofile>和<springproperty>,推荐在 spring boot 项目中使用
四、logback-spring.xml 完整配置
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- 从 application.yml 读取属性 -->
<springproperty scope="context" name="app_name"
source="spring.application.name" defaultvalue="myapp"/>
<springproperty scope="context" name="log_path"
source="logging.file.path" defaultvalue="logs"/>
<!-- 日志格式 -->
<property name="console_pattern"
value="%d{yyyy-mm-dd hh:mm:ss.sss} [%thread] %-5level %logger{36} - %msg%n"/>
<property name="file_pattern"
value="%d{yyyy-mm-dd hh:mm:ss.sss} [%thread] %-5level %logger{36} - %msg%n"/>
<!-- 控制台输出 -->
<appender name="console" class="ch.qos.logback.core.consoleappender">
<encoder>
<pattern>${console_pattern}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 全量日志文件 -->
<appender name="file" class="ch.qos.logback.core.rolling.rollingfileappender">
<file>${log_path}/${app_name}.log</file>
<rollingpolicy class="ch.qos.logback.core.rolling.sizeandtimebasedrollingpolicy">
<!-- 按天和大小滚动 -->
<filenamepattern>${log_path}/${app_name}.%d{yyyy-mm-dd}.%i.log.gz</filenamepattern>
<maxfilesize>100mb</maxfilesize>
<maxhistory>30</maxhistory>
<totalsizecap>3gb</totalsizecap>
</rollingpolicy>
<encoder>
<pattern>${file_pattern}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 错误日志单独文件 -->
<appender name="error_file" class="ch.qos.logback.core.rolling.rollingfileappender">
<file>${log_path}/${app_name}-error.log</file>
<!-- 只记录 error 级别 -->
<filter class="ch.qos.logback.classic.filter.levelfilter">
<level>error</level>
<onmatch>accept</onmatch>
<onmismatch>deny</onmismatch>
</filter>
<rollingpolicy class="ch.qos.logback.core.rolling.sizeandtimebasedrollingpolicy">
<filenamepattern>${log_path}/${app_name}-error.%d{yyyy-mm-dd}.%i.log.gz</filenamepattern>
<maxfilesize>50mb</maxfilesize>
<maxhistory>60</maxhistory>
</rollingpolicy>
<encoder>
<pattern>${file_pattern}</pattern>
<charset>utf-8</charset>
</encoder>
</appender>
<!-- 异步 appender(提升性能) -->
<appender name="async_file" class="ch.qos.logback.classic.asyncappender">
<!-- 队列大小,默认 256 -->
<queuesize>512</queuesize>
<!-- 队列剩余容量小于此比例时,丢弃 trace/debug/info 级别日志 -->
<discardingthreshold>0</discardingthreshold>
<!-- 不丢弃任何级别日志 -->
<includecallerdata>false</includecallerdata>
<!-- 引用实际的 appender -->
<appender-ref ref="file"/>
</appender>
<!-- 包级别日志配置 -->
<logger name="com.example.mapper" level="debug"/>
<logger name="org.springframework.web" level="info"/>
<logger name="org.mybatis" level="info"/>
<!-- 开发环境:控制台输出 debug -->
<springprofile name="dev">
<root level="debug">
<appender-ref ref="console"/>
</root>
</springprofile>
<!-- 测试环境:控制台 + 文件 -->
<springprofile name="test">
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="async_file"/>
</root>
</springprofile>
<!-- 生产环境:只写文件,异步 -->
<springprofile name="prod">
<root level="info">
<appender-ref ref="async_file"/>
<appender-ref ref="error_file"/>
</root>
</springprofile>
</configuration>五、logback.xml 完整配置(无 profile 支持)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<property name="log_path" value="logs"/>
<property name="log_pattern"
value="%d{yyyy-mm-dd hh:mm:ss.sss} [%thread] %-5level %logger{36} - %msg%n"/>
<appender name="console" class="ch.qos.logback.core.consoleappender">
<encoder>
<pattern>${log_pattern}</pattern>
</encoder>
</appender>
<appender name="file" class="ch.qos.logback.core.rolling.rollingfileappender">
<file>${log_path}/app.log</file>
<rollingpolicy class="ch.qos.logback.core.rolling.timebasedrollingpolicy">
<filenamepattern>${log_path}/app.%d{yyyy-mm-dd}.log</filenamepattern>
<maxhistory>30</maxhistory>
</rollingpolicy>
<encoder>
<pattern>${log_pattern}</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="file"/>
</root>
</configuration>六、核心组件详解
6.1 appender(输出目的地)
| appender | 说明 |
|---|---|
consoleappender | 输出到控制台 |
fileappender | 输出到文件 |
rollingfileappender | 输出到文件,支持按时间/大小滚动 |
asyncappender | 异步输出,包装其他 appender |
smtpappender | 邮件发送(用于告警) |
dbappender | 写入数据库 |
6.2 encoder(编码器)
控制日志输出的格式:
<encoder>
<pattern>%d{yyyy-mm-dd hh:mm:ss.sss} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>常用占位符:
| 占位符 | 含义 |
|---|---|
%d | 日期时间 |
%thread | 线程名 |
%-5level | 日志级别,左对齐占 5 字符 |
%logger{36} | 日志名称,最多 36 字符 |
%msg | 日志消息 |
%n | 换行符 |
%x{key} | mdc 中的值 |
%m | 方法名(性能开销大) |
%l | 行号(性能开销大) |
%c | 类名(性能开销大) |
6.3 filter(过滤器)
控制哪些日志被输出:
levelfilter(级别过滤器):
<filter class="ch.qos.logback.classic.filter.levelfilter">
<level>error</level>
<onmatch>accept</onmatch>
<onmismatch>deny</onmismatch>
</filter>thresholdfilter(阈值过滤器):
<!-- 只输出 warn 及以上级别 -->
<filter class="ch.qos.logback.classic.filter.thresholdfilter">
<level>warn</level>
</filter>evaluatorfilter(表达式过滤器):
<filter class="ch.qos.logback.core.filter.evaluatorfilter">
<evaluator>
<expression>return message.contains("敏感信息");</expression>
</evaluator>
<onmatch>deny</onmatch>
<onmismatch>neutral</onmismatch>
</filter>6.4 rollingpolicy(滚动策略)
timebasedrollingpolicy(按时间滚动):
<rollingpolicy class="ch.qos.logback.core.rolling.timebasedrollingpolicy">
<filenamepattern>logs/app.%d{yyyy-mm-dd}.log</filenamepattern>
<maxhistory>30</maxhistory>
</rollingpolicy>sizeandtimebasedrollingpolicy(按时间和大小滚动):
<rollingpolicy class="ch.qos.logback.core.rolling.sizeandtimebasedrollingpolicy">
<filenamepattern>logs/app.%d{yyyy-mm-dd}.%i.log.gz</filenamepattern>
<maxfilesize>100mb</maxfilesize>
<maxhistory>30</maxhistory>
<totalsizecap>3gb</totalsizecap>
</rollingpolicy>| 属性 | 说明 |
|---|---|
filenamepattern | 日志文件命名模式,%d 日期,%i 索引,.gz 自动压缩 |
maxfilesize | 单文件最大大小 |
maxhistory | 保留的历史文件天数 |
totalsizecap | 所有日志文件总大小上限 |
七、在代码中使用日志
import org.slf4j.logger;
import org.slf4j.loggerfactory;
@service
public class userservice {
private static final logger log = loggerfactory.getlogger(userservice.class);
public user getuser(long id) {
log.debug("查询用户,id: {}", id);
try {
user user = usermapper.selectbyid(id);
log.info("查询用户成功,id: {}, name: {}", id, user.getname());
return user;
} catch (exception e) {
log.error("查询用户失败,id: {}", id, e);
throw e;
}
}
}
使用 lombok 的 @slf4j 可以省略 logger 声明:
@slf4j
@service
public class userservice {
public user getuser(long id) {
log.debug("查询用户,id: {}", id);
// ...
}
}
八、mdc(mapped diagnostic context)
mdc 用于在日志中添加自定义上下文信息,比如请求 id、用户 id、追踪 id 等。
@component
public class tracefilter implements filter {
@override
public void dofilter(servletrequest request, servletresponse response,
filterchain chain) throws ioexception, servletexception {
string traceid = uuid.randomuuid().tostring().replace("-", "");
mdc.put("traceid", traceid);
try {
chain.dofilter(request, response);
} finally {
mdc.clear(); // 必须清理,否则线程复用时数据污染
}
}
}
在日志格式中引用 mdc:
<pattern>%d{yyyy-mm-dd hh:mm:ss.sss} [%thread] [%x{traceid}] %-5level %logger{36} - %msg%n</pattern>输出效果:
2026-09-11 17:38:34.123 [http-nio-8080-exec-1] [a1b2c3d4e5f6] info c.e.userservice - 查询用户,id: 1
注意事项:
- mdc 基于
threadlocal,异步线程中无法直接获取父线程的 mdc - 使用
@async或线程池时,需要手动传递 mdc 或使用taskdecorator - 请求结束后必须调用
mdc.clear(),否则线程池复用时会残留数据
九、异步日志与性能优化
<appender name="async_file" class="ch.qos.logback.classic.asyncappender">
<!-- 队列大小,默认 256,建议设大一些 -->
<queuesize>1024</queuesize>
<!-- 队列剩余容量百分比,低于此值时丢弃 trace/debug/info -->
<discardingthreshold>20</discardingthreshold>
<!-- 是否包含调用者数据(方法名、行号等),会带来性能开销 -->
<includecallerdata>false</includecallerdata>
<!-- 队列满时是否阻塞,false 表示丢弃 -->
<neverblock>false</neverblock>
<appender-ref ref="file"/>
</appender>异步日志的核心参数:
| 参数 | 默认值 | 说明 |
|---|---|---|
queuesize | 256 | 队列大小,越大越不容易丢日志 |
discardingthreshold | 20 | 队列剩余 20% 时,丢弃低级别日志 |
includecallerdata | false | 是否记录调用者信息,开启后有性能开销 |
neverblock | false | true 时队列满直接丢弃,不阻塞业务线程 |
性能建议:
- 生产环境使用
asyncappender,减少日志对业务线程的阻塞 includecallerdata保持false,除非确实需要方法名和行号- 合理设置日志级别,避免 debug/trace 日志拖慢性能
十、spring boot 配置文件控制日志
除了 logback-spring.xml,也可以在 application.yml 中配置日志:
logging:
level:
root: info
com.example: debug
org.springframework.web: debug
file:
name: logs/myapp.log
logback:
rollingpolicy:
max-file-size: 100mb
max-history: 30
total-size-cap: 3gb
pattern:
console: "%d{yyyy-mm-dd hh:mm:ss.sss} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-mm-dd hh:mm:ss.sss} [%thread] %-5level %logger{36} - %msg%n"application.yml 中的配置会被 logback-spring.xml 中的配置覆盖。两者的优先级是:logback-spring.xml > application.yml。
十一、常见问题与排查
1. 日志文件不生成
原因: 文件路径不存在或权限不足。
解决: 检查 log_path 指向的目录是否存在,应用是否有写入权限。
2. 日志输出重复
原因: 配置了多个 appender,或者父 logger 和子 logger 都输出。
解决: 检查 additivity 属性,设置为 false 可以阻止日志向父 logger 传递。
<logger name="com.example" level="debug" additivity="false">
<appender-ref ref="console"/>
</logger>3. 日志级别配置不生效
原因: 可能是配置文件没有被加载,或者被其他配置覆盖。
解决: 检查 logback-spring.xml 是否在 classpath 根目录下,启动日志中是否有 logback 初始化信息。
4. 中文乱码
原因: 编码未指定。
解决: 在 <encoder> 中添加 <charset>utf-8</charset>。
5. 日志文件滚动后不压缩
原因: filenamepattern 中缺少 .gz 或 .zip 后缀。
解决: 修改为 <filenamepattern>logs/app.%d{yyyy-mm-dd}.log.gz</filenamepattern>。
十二、总结
| 维度 | 核心要点 |
|---|---|
| 依赖 | spring boot 项目自动包含 logback,无需手动引入 |
| 配置文件 | spring boot 推荐 logback-spring.xml,支持 profile 和属性注入 |
| appender | 控制台、文件、异步、滚动文件,按需组合 |
| 日志级别 | trace < debug < info < warn < error,级别越高越严重 |
| mdc | 在日志中添加上下文信息(如 traceid),便于问题追踪 |
| 异步日志 | 使用 asyncappender 提升性能,注意队列大小和丢弃策略 |
| 滚动策略 | 按时间或大小滚动,设置 maxhistory 和 totalsizecap 防止磁盘占满 |
| 最佳实践 | 开发环境控制台输出,生产环境异步写文件,错误日志单独归档 |
以上就是springboot集成logback日志框架的完全指南的详细内容,更多关于springboot集成logback日志框架的资料请关注代码网其它相关文章!
发表评论