在logback中实现日志敏感信息脱敏,最常用且推荐的方式是自定义encoder(或其子类layout),在日志事件被序列化输出前对message、mdc、arguments等动态清洗,需继承layoutwrappingencoder并复用patternlayout能力,分层处理mdc、结构化message及json日志,确保全链路无侵入脱敏。

在 Logback 中实现日志敏感信息脱敏,最常用且推荐的方式是**自定义 Encoder(或其子类 Layout)**,在日志事件被序列化输出前对日志内容(如 message、MDC、arguments)进行动态清洗。不建议直接重写 Layout 做字符串拼接级脱敏(易漏、难维护),而应基于 PatternLayout 扩展,或更稳妥地使用 Encoder 封装脱敏逻辑。
核心思路:在 Encoder 中拦截并处理 ILoggingEvent
Logback 的日志输出流程为:Logger → Appender → Encoder → OutputStream。其中 Encoder 负责将 ILoggingEvent 转为字节数组。我们可继承 LayoutWrappingEncoder 或直接实现 Encoder,在 encode(ILoggingEvent) 方法中对日志内容做脱敏处理。
- 脱敏目标通常包括:
event.getFormattedMessage()(格式化后的 message)、event.getArgumentArray()(占位符参数)、event.getMDCPropertyMap()(MDC 上下文,如 traceId、userId、手机号等) - 避免修改原始 event 对象(线程不安全),应在 encode 过程中生成新字符串
- 脱敏规则建议外置(如配置正则 + 替换模板),便于热更新和统一管理
推荐做法:继承 LayoutWrappingEncoder 实现可配置脱敏 Encoder
复用 Logback 原生 PatternLayout 的能力(支持 %d、%m、%X 等),仅在其输出结果上做后处理脱敏,兼顾灵活性与稳定性。
- 定义脱敏配置类(如
SensitiveRule),支持字段名匹配(phone、idCard)、正则模式(1[3-9]\d{9})、掩码方式(138****1234) - 自定义
SensitiveEncoder继承LayoutWrappingEncoder<iloggingevent></iloggingevent> - 重写
encode(ILoggingEvent event):- 调用
layout.doLayout(event)获取原始日志字符串 - 提取 MDC 中的敏感键值(如
X-User-Phone)、解析 message 中 JSON 或 key=value 结构(可选) - 对字符串整体执行多轮脱敏(先 MDC,再 message,再 arguments 字符串化后)
- 返回脱敏后的字节数组:
result.getBytes(StandardCharsets.UTF_8)
- 调用
- 在
logback-spring.xml中声明该 encoder,并配置 layout 和脱敏规则 bean
实用技巧:精准识别与安全脱敏
单纯用正则全局替换容易误伤(如把订单号 1234567890 当作手机号)。应分层处理:
-
上下文优先:优先检查 MDC 中已知敏感 key(
userPhone、idCard、email),按预设规则替换,不依赖正则 -
Message 结构化解析:若日志 message 是结构化文本(如
"login success, userId=123, phone=13812345678"),可用简单正则(phone|mobile|tel)=([^\s,]+)提取并脱敏,而非匹配所有 11 位数字 -
JSON 日志专用处理:若使用
JsonLayout,更推荐自定义JsonProvider或在JsonLayout外包一层脱敏Encoder,对 JSON 字符串做JSONObject解析 + 字段遍历脱敏,确保只处理指定 key -
性能注意:避免在 encode 中做复杂 JSON 解析或大量正则匹配;对高频日志,可加简单开关(如
if (isSensitiveLog(event)))跳过非敏感场景
配置示例(logback-spring.xml)
以下为简化版配置示意:
<encoder class="com.example.log.SensitiveEncoder"><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern></layout><!-- 可注入脱敏规则 Bean 或通过 property 配置 --><rules><rule key="phone" pattern="1[3-9]d{9}" mask="138****1234"></rule><rule key="idCard" pattern="d{17}[dXx]" mask="110101**********123X"></rule></rules></encoder>
对应 Java 类需提供 setRules(...) 方法接收配置,并在 encode 中应用。
不复杂但容易忽略的是:脱敏必须覆盖所有日志入口 —— 不仅是普通 logger.info(),还包括异常堆栈(event.getThrowableProxy())、MDC 全局字段、甚至异步日志上下文传递。只要在 Encoder 层统一拦截 ILoggingEvent,就能做到无侵入、全链路防护。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











