Logback 学习笔记

Logback 学习笔记

一、Java 日志体系总览

1.1 三层结构

复制代码
你的代码(import org.slf4j.Logger)
   ↓
SLF4J(门面/接口层)------ 只定义 API,不干活
   ↓
Logback / Log4j2 / JUL(实际干活的实现层)

1.2 为什么需要门面

Java 生态里有多个日志框架(Log4j、JUL、Commons-Logging、Log4j2、Logback),第三方库各用各的。SLF4J 统一了接口,让所有日志最终汇聚到一个实现中,用一份配置管理。

1.3 门面模式(Facade Pattern)

GoF 23 种设计模式之一(结构型)。核心思想:为复杂子系统提供简化的统一接口。

Java 生态中的门面案例:

  • SLF4J:日志门面,底层可换 Logback/Log4j2
  • JDBC:数据库门面,底层可换 MySQL/PostgreSQL/Oracle 驱动
  • Servlet API:HTTP 门面,底层可换 Tomcat/Jetty/Undertow
  • Spring Cache:缓存门面,底层可换 Caffeine/Redis/EhCache

1.4 SLF4J 绑定机制

SLF4J 启动时通过 Class.forName("org.slf4j.impl.StaticLoggerBinder") 找到 classpath 上的实现。logback-classic.jar 里提供了这个类,所以 SLF4J 绑定到 Logback。

1.5 桥接器

让使用其他日志框架的第三方库也走 SLF4J:

  • log4j-over-slf4j:Log4j API → SLF4J
  • jul-to-slf4j:JUL → SLF4J
  • jcl-over-slf4j:Commons-Logging → SLF4J

Spring Boot 的 spring-boot-starter-logging 自动引入了这些桥接器。


二、Logback 三大核心概念

2.1 Logger(记录器)

  • 是日志的入口,代码里 log.info() 调的就是它
  • 有唯一名字:LoggerFactory.getLogger(类名)LoggerFactory.getLogger("自定义字符串")
  • 有层级关系:按 . 分隔形成树,root 是所有 Logger 的祖先
  • 有日志级别:TRACE < DEBUG < INFO < WARN < ERROR,低于阈值的不输出
  • 有 additivity 属性:默认 true,日志会向上传递给父 Logger

2.2 Appender(输出器)

决定日志写到哪里:

Appender 用途
ConsoleAppender 输出到控制台
RollingFileAppender 输出到文件,按大小/时间滚动切割
AsyncAppender 包装器,把别的 appender 变成异步
SMTPAppender 发邮件告警
SocketAppender 发到远程服务器

一个 Logger 可以挂多个 Appender。

2.3 Encoder + Pattern(格式化器)

用 pattern 字符串定义日志输出格式。


三、LoggerFactory.getLogger 两种用法

3.1 传类名(99% 的场景)

java 复制代码
LoggerFactory.getLogger(ApiCacheAdvice.class)
// 等价于
LoggerFactory.getLogger("com.xiaomi.mina.client.v1.aop.ApiCacheAdvice")

好处:

  • 日志里能看出哪个类打的(pattern 里 %logger 会显示类名)
  • 可以按包名批量控制级别(<logger name="com.xiaomi" level="DEBUG">

3.2 传自定义字符串(特殊场景)

java 复制代码
LoggerFactory.getLogger("ACCESS_LOGGER")

用于需要独立输出到单独文件的场景(访问日志、慢 SQL 日志、审计日志等)。配合 logback.xml 里的 <logger name="ACCESS_LOGGER"> 使用。

3.3 @Slf4j 等价于什么

java 复制代码
@Slf4j
public class MyClass { ... }
// Lombok 编译时自动生成:
private static final Logger log = LoggerFactory.getLogger(MyClass.class);

四、mina-client logback.xml 逐段解读

4.1 变量定义

xml 复制代码
<property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-...}"/>
<property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-...}"/>
<property scope="context" name="APP_NAME" value="mina-client-api"/>
<property name="LOG_HOME" value="${log.logdir:-logs}"/>
<property scope="context" name="LOG_ROOT_LEVEL" value="INFO"/>

${变量名:-默认值} 语法:先找变量,找不到就用默认值。

变量查找优先级:logback <property> → Java 系统属性 → 环境变量 → 默认值

scope="context" 表示在整个 logback 上下文中可见(包括 include 的文件)。不加 scope 默认是 local(只在当前文件)。

4.2 LOG_HOME 的实际值

  • 生产环境:Dockerfile/start.sh 里 -Dlog.logdir=/home/work/logs → LOG_HOME = /home/work/logs
  • 本地开发:没有 -D 参数 → 走默认值 logs(相对路径,项目根目录下的 logs/)

4.3 include

xml 复制代码
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
  • defaults.xml:注册 %clr 颜色转换器 + 定义默认变量 + 屏蔽第三方库噪音日志
  • console-appender.xml:提供一个现成的 CONSOLE appender(被项目自己的覆盖了)

4.4 access appender --- 访问日志

xml 复制代码
<appender name="access" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <File>${LOG_HOME}/access.${APP_NAME}.log</File>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <FileNamePattern>${LOG_HOME}/access.${APP_NAME}.%d{yyyyMMdd}.%i.log</FileNamePattern>
        <MaxHistory>1</MaxHistory>       <!-- 只保留1天(已写入数据工场) -->
        <maxFileSize>100MB</maxFileSize>  <!-- 单文件超100MB就滚动 -->
    </rollingPolicy>
</appender>
  • %d{yyyyMMdd} = 日期,%i = 当天序号
  • 归档示例:access.mina-client-api.20260604.0.log

4.5 asyncAccess --- 异步包装

xml 复制代码
<appender name="asyncAccess" class="ch.qos.logback.classic.AsyncAppender">
    <discardingThreshold>0</discardingThreshold>  <!-- 队列满不丢日志(会阻塞) -->
    <queueSize>1024</queueSize>                    <!-- 内存队列容量 -->
    <includeCallerData>true</includeCallerData>    <!-- 保留调用栈信息 -->
    <appender-ref ref="access"/>                   <!-- 包装 access appender -->
</appender>

AsyncAppender 不是独立输出器,是包装器。业务线程只把消息塞进队列就返回,后台线程负责写盘。没有日志路径是因为它自己不写文件,转交给内部引用的 access appender 写。

discardingThreshold=0 的代价:磁盘 IO 太慢时队列满了会阻塞业务线程。默认值 20% 会丢弃低级别日志保护业务。这里配 0 说明访问日志一条不能丢。

4.6 FILE_ALL --- 全量日志

xml 复制代码
<File>${LOG_HOME}/all.${APP_NAME}.log</File>
<MaxHistory>7</MaxHistory>     <!-- 保留7天 -->
<maxFileSize>10MB</maxFileSize>

4.7 FILE_ERROR --- 错误日志

xml 复制代码
<filter class="ch.qos.logback.classic.filter.LevelFilter">
    <level>ERROR</level>
    <OnMismatch>DENY</OnMismatch>
    <OnMatch>ACCEPT</OnMatch>
</filter>

LevelFilter 只收 ERROR,其他级别全拒绝。

4.8 ACCESS_LOGGER --- 自定义命名 Logger

xml 复制代码
<logger name="ACCESS_LOGGER" additivity="false" level="INFO">
    <appender-ref ref="asyncAccess"/>
</logger>
  • additivity="false":禁止向上传递,日志不会进 root 的 appender(不会重复输出到 all/console)
  • 只绑定 asyncAccess 一个 appender → 日志只进 access.log

4.9 root logger --- 兜底

xml 复制代码
<root level="${LOG_ROOT_LEVEL}">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE_ALL"/>
    <appender-ref ref="FILE_ERROR"/>
</root>

所有没被专门配置 <logger> 的 Logger 都走 root。@Slf4j 生成的业务日志同时输出到控制台 + all 文件 + err 文件。


五、Pattern 详解

5.1 FILE_LOG_PATTERN

复制代码
%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%X{trace_id}|%15.15t|%-40.40logger{39}|%m%n%xException
片段 含义 示例输出
%d{yyyy-MM-dd HH:mm:ss.SSS} 时间(毫秒精度) 2026-06-05 11:30:45.123
%-5level 日志级别,左对齐宽度5 INFO
%X{trace_id} MDC 变量(链路追踪ID) abc123def456
%15.15t 线程名,固定宽度15 http-nio-8080-1
%-40.40logger{39} Logger名,缩写到39字符,左对齐宽度40 c.x.m.client.v1.aop.ApiCacheAdvice
%m 日志消息正文 缓存命中 key=xxx
%n 换行
%xException 异常堆栈 java.lang.NullPointerException...

最终输出示例:

复制代码
2026-06-05 11:30:45.123|INFO |abc123def456|http-nio-8080-1|c.x.m.client.v1.aop.ApiCacheAdvice       |缓存命中 key=xxx

5.2 CONSOLE_LOG_PATTERN

复制代码
%d{yyyy-MM-dd HH:mm:ss.SSS} %clr(${level:-%5p}) --- [%15.15t] %clr(%-40.40logger{39}){cyan} : %m%n%xEx
  • %clr(内容):自动按级别着色(INFO=绿, WARN=黄, ERROR=红),只在控制台有效
  • %clr(内容){cyan}:固定青色
  • 用空格 + --- + [] 分隔(人眼友好)

5.3 格式化占位符速查

符号 含义
%d 日期时间
%p%level 日志级别
%t%thread 线程名
%logger{N} Logger 名(N=最大字符数,超长会缩写包名)
%m%msg 消息体
%n 换行符
%X{key} MDC 变量
%xEx / %xException 异常堆栈(含包信息)
%-N 左对齐,最小宽度N
%N.N 最小宽度.最大宽度(超长截断)

六、同步 vs 异步

Logger 绑定的 appender 同步/异步
@Slf4j 生成的(类名 Logger) CONSOLE + FILE_ALL + FILE_ERROR 同步
ACCESS_LOGGER(手动创建的) asyncAccess 异步

业务代码里的 log.infolog.error 是同步写磁盘的。只有访问日志走异步。


七、Spring Boot 与 logback.xml 的交互

7.1 两种配日志的方式

方式 适合
application.yml 的 logging.* 简单项目,不想写 logback.xml
自定义 logback.xml 复杂项目,需要精细控制

7.2 有 logback.xml 时 yml 配置的生效情况

yml 配置 是否生效 原因
logging.level.root 生效 Spring Boot 强制调 API 设级别
logging.level.com.xxx 生效 同上
logging.file.name 看情况 注入为 LOG_FILE 变量,logback.xml 里引用了才有用
logging.pattern.console 看情况 注入为 CONSOLE_LOG_PATTERN 变量,logback.xml 里引用了才有用

7.3 Spring Boot 注入变量的机制

复制代码
yml: logging.pattern.console = "%d %p %m%n"
  → Spring Boot: System.setProperty("CONSOLE_LOG_PATTERN", "%d %p %m%n")
  → logback 解析 ${CONSOLE_LOG_PATTERN:-默认值}
  → 找到系统属性,用它的值

八、常用配置场景

  1. 按环境切换<springProfile name="dev"> / <springProfile name="production">
  2. 第三方库降噪<logger name="org.redisson" level="WARN"/>
  3. 独立日志文件:命名 Logger + additivity=false + 单独 appender
  4. 全异步:所有 appender 都用 AsyncAppender 包一层
  5. 慢 SQL 日志:和 ACCESS_LOGGER 同一套路
  6. ERROR 告警:SMTPAppender 或 Prometheus + AlertManager

九、MDC(Mapped Diagnostic Context)

线程级的键值对变量,用于链路追踪。

java 复制代码
MDC.put("trace_id", "abc123");   // 请求进入时设置
log.info("处理中");              // 日志自动带上 %X{trace_id} = abc123
MDC.remove("trace_id");          // 请求结束时清除(避免线程池复用污染)

Pattern 里用 %X{trace_id} 引用。同一个请求在多个类里打的日志都带同一个 trace_id,grep 一下就能串起整条链路。

相关推荐
数智工坊1 小时前
周志华《Machine Learning》学习笔记--第十三章--半监督学习
笔记·学习·机器学习
AI_零食1 小时前
鸿蒙原生 ArkTS:margin 溢出、Row 弹性分配与 alignItems 的交互
学习·华为·开源·harmonyos·鸿蒙·鸿蒙系统
AOwhisky1 小时前
MySQL 学习笔记(第七期):高可用架构进阶与综合项目实战
linux·运维·笔记·学习·mysql·高可用·mha
踏着七彩祥云的小丑1 小时前
嵌入式测试学习第 30 天:功耗测试、待机电流、工作电流测试
单片机·嵌入式硬件·学习
AI_零食1 小时前
鸿蒙原生 ArkTS:border 的盒模型、深层嵌套约束传递与 scale 缩放
学习·华为·harmonyos·鸿蒙·鸿蒙系统
searchforAI2 小时前
培训视频转文字后怎么做团队复盘?把本地视频整理成AI笔记的实操方案
人工智能·笔记·ai·whisper·音视频·语音识别·腾讯会议
鲁子狄2 小时前
lrnev:让 AI 协作开发「有记忆、可追溯」的项目治理引擎 | 零模型依赖,文件即真相
人工智能·笔记·gpt·ai·ai编程
syagain_zsx2 小时前
Linux进程控制学习总结(2/2)
linux·运维·学习
中屹指纹浏览器2 小时前
2026指纹浏览器集群分布式部署架构、负载均衡与机房硬件适配方案
经验分享·笔记