捕获异常后应直接传递Throwable对象给日志框架而非仅用getMessage(),并确保日志pattern含%ex,JVM需加-XX:-OmitStackTraceInFastThrow避免堆栈丢失,自定义堆栈时用printStackTrace(new PrintWriter(sw))。

捕获异常后想看到完整堆栈,关键不是“怎么打印”,而是“别删掉它”——很多问题源于无意中只取了 e.getMessage() 或拼接字符串,把堆栈信息直接丢弃了。
用日志框架传 Throwable 对象
主流日志框架(SLF4J + Logback / Log4j2)都支持把异常对象作为最后一个参数传入,自动展开完整堆栈和 cause 链:
- ✅ 正确:
logger.error("订单创建失败,用户ID: {}", userId, e); - ❌ 错误:
logger.error("订单创建失败: " + e.getMessage());(拼字符串,堆栈消失) - ❌ 错误:
logger.error("订单创建失败", e.getMessage());(把字符串当异常传,不识别)
检查日志输出格式是否含堆栈占位符
即使代码传了异常,如果日志 pattern 没配 %ex,堆栈依然不会显示。以 Logback 为例:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 确保
<pattern>中包含%ex(标准堆栈)或%xEx(带 MDC 的堆栈) - 错误配置示例:
%d %-5level [%thread] %logger - %msg%n→ 缺%ex,堆栈不出现 - 推荐配置片段:
%d{HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%ex%n
注意 JVM 快速抛出优化导致堆栈丢失
生产环境高频触发的 NullPointerException、IllegalArgumentException 等内置异常,JVM 可能复用无堆栈的预分配实例:
立即学习“Java免费学习笔记(深入)”;
- 现象:前几次日志有堆栈,后续变成
java.lang.NullPointerException: null(无 at 行) - 解决:JVM 启动参数加上
-XX:-OmitStackTraceInFastThrow - 该参数从 JDK 6u21 起支持,不影响性能,建议生产环境统一启用
需要自定义或脱敏时手动构造堆栈字符串
比如要过滤内部类路径、写入数据库、或添加前缀说明,可用 PrintWriter + StringWriter 获取可编辑的堆栈字符串:
- 不要用
e.toString()或Arrays.toString(e.getStackTrace()),它们不包含异常头、cause 链或格式化结构 - 标准写法:
StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); String stackTrace = sw.toString(); // 包含完整堆栈+cause链 logger.error("支付回调处理异常,traceId: {},堆栈: {}", traceId, stackTrace);


















