java日志应完整记录异常堆栈和业务上下文,推荐logback+slf4j组合,通过slf4j占位符+异常参数(异常必须为最后一个参数)、mdc绑定traceid/userid/orderno等上下文、敏感信息统一脱敏、jsonlayout输出结构化日志实现优雅记录。

在 Java 日志中完整记录异常堆栈和业务上下文,关键不是简单调用 e.printStackTrace() 或只打 e.getMessage(),而是让日志既包含可定位的堆栈轨迹,又附带能还原现场的业务变量(如订单号、用户 ID、请求参数等)。Logback + SLF4J 是目前最主流且灵活的组合,配合结构化日志和 MDC 可以做到真正“优雅”。
用 SLF4J 的占位符 + 异常参数记录堆栈
SLF4J 支持将 Throwable 作为最后一个参数传入日志方法,框架会自动将其堆栈信息追加到日志末尾,且不影响格式化占位符。这是最基础也最关键的写法:
logger.error("订单支付失败,订单号:{},用户ID:{}", orderNo, userId, e);
⚠️ 注意:异常对象必须是最后一个参数;若放在中间或前面,会被当成普通对象 toString(),堆栈就丢了。
用 MDC 绑定业务上下文,避免重复传参
MDC(Mapped Diagnostic Context)是 SLF4J 提供的线程级键值存储,适合存放一次请求共有的上下文字段。它能自动注入到每条日志中,无需在每个 log 语句里手动拼接:
- 在 Web 过滤器(如
OncePerRequestFilter)中提取请求头、参数或解析后的业务 ID,放入 MDC:
MDC.put("traceId", request.getHeader("X-Trace-ID"));
MDC.put("userId", String.valueOf(getCurrentUserId()));
MDC.put("orderNo", request.getParameter("orderNo"));
- 在 Logback 配置中使用
%X{key}输出 MDC 字段(例如:%d [%X{traceId} %X{userId}] %-5level %logger - %msg%n); - 请求结束时务必调用
MDC.clear(),防止线程复用导致上下文污染。
对敏感信息做脱敏,再写入日志
订单号、手机号、身份证号等不能明文落盘。不要在日志语句里自己拼接脱敏逻辑(易遗漏、难维护),推荐统一拦截处理:
- 自定义
Converter或Layout,对 MDC 中特定 key(如idCard、phone)自动掩码; - 或使用日志门面层封装工具类,例如:
logger.error("用户登录异常,手机号:{},IP:{}",
Desensitization.phone(userPhone), clientIp, e);
脱敏逻辑集中管理,后续调整(如从 138****1234 改为 138****234)只需改一处。
必要时记录结构化日志(JSON 格式)
当排查链路问题需要被其他系统(如 ELK、SkyWalking)消费时,纯文本日志解析成本高。Logback 支持 JsonLayout,把上下文字段、异常堆栈、时间戳等序列化为 JSON:
- 配置
JsonLayout并启用includeException和appendLineSeparator; - MDC 中的字段会自动成为 JSON 的 top-level 字段;
- 异常堆栈转为
exception字段(含 message、type、stackTrace 数组),便于 Kibana 聚合分析。
这样一条日志就是一个自描述的事件对象,不再依赖日志格式约定。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











