Java日志脱敏核心是在日志写入前拦截清洗原始字符串,重点覆盖Throwable的getMessage()/toString()、参数对象序列化结果及最终日志行;推荐用Logback MessageConverter做正则掩码,并避免toString()泄露敏感信息。

Java中日志脱敏在打印自定义异常 message 时做正则掩码,核心不是“改异常类”,而是**在日志写入前拦截并清洗原始字符串内容**。因为自定义异常的 getMessage() 或 toString() 很可能直接拼接了含敏感字段(如密码、token、手机号)的原始信息,一旦被 Logback/Log4j 拿去格式化输出,就已泄露。
重点拦截三处日志生成环节
敏感字段常藏在异常 message、堆栈 trace、或日志参数中。必须覆盖以下位置:
- Throwable 的
getMessage()和toString()返回值(含 getCause() 链递归) - 日志框架对参数对象(如 User、OrderRequest)序列化后的字符串表示
- 最终拼接出的完整日志行(即
event.getFormattedMessage())
用 MessageConverter 对 message 做正则掩码(推荐)
Logback 提供 MessageConverter,它在日志格式化阶段介入,能拿到原始 message 字符串,适合轻量级正则掩码:
- 继承
ch.qos.logback.classic.pattern.MessageConverter - 重写
convert(ILoggingEvent event),获取event.getFormattedMessage() - 对字符串执行多轮正则替换,例如:
身份证号:\d{17}[\dXx] → **************\d{4}
密码参数:pwd=([^;\s]+) → pwd=***
JDBC 连接串:jdbc:[^\s]*?://[^@]+@ → jdbc:mysql://root:***@localhost
避免 toString() 泄露敏感内容
自定义异常若重写 toString(),严禁直接调用 super.toString() —— 它会把底层 SQLException 的完整 URL(含密码)原样带出来。正确写法是:
立即学习“Java免费学习笔记(深入)”;
- 只拼接可控字段:
return getClass().getSimpleName() + "[code=" + code + ", msg=" + message + "]"; - 不主动拼接
getCause().getMessage(),除非该 cause 已被脱敏器处理过 - 构造异常时传入 clean message,而非原始异常的 getMessage()
配合 Appender 统一清洗 Throwable
更彻底的做法是自定义 Logback Appender,从源头过滤异常对象:
- 继承
AppenderBase<ILoggingEvent> - 在
append()中检查event.getThrowableProxy() - 递归遍历 cause 链,对每个
getMessage()和每个StackTraceElement.toString()执行相同正则掩码 - 再交由父类输出,业务代码完全无感



















