应直接将Throwable对象作为独立参数传给日志方法,如logger.error("数据库查询失败", e),以保留完整堆栈跟踪;避免e.toString()、e.getMessage()或单独传e等丢失上下文或堆栈的写法。

在 Java 中记录异常堆栈信息,关键是把 Throwable 对象(如 Exception)直接传给日志方法,而不是只记录 e.toString() 或 e.getMessage() —— 后者会丢失堆栈跟踪(stack trace),无法定位问题根源。
用 logger.error() 传入异常对象
主流日志框架(Log4j、Logback、SLF4J)都支持在日志方法中同时传入消息和 Throwable。这是最标准、最推荐的方式:
- SLF4J(推荐):
logger.error("数据库查询失败", e); - Log4j2:
logger.error("数据库查询失败", e); - Logback(底层常配合 SLF4J):
logger.warn("文件读取超时", e);
这样日志中会自动打印完整堆栈,包括异常类型、消息、每一层调用位置(类名、方法名、行号)。
避免常见错误写法
以下写法看似能输出异常,但实际会丢失关键调试信息:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
logger.error("操作失败: " + e);→ 调用e.toString(),无堆栈 -
logger.error("操作失败: " + e.getMessage());→ 只有提示文字,无上下文和调用链 -
logger.error(e);(无消息)→ 堆栈虽有,但缺少业务上下文(比如“哪次请求”“哪个用户”“什么操作”)
务必保证:**有描述性消息 + 异常对象作为独立参数**。
在 catch 块中正确捕获并记录
典型安全写法示例:
try {
processOrder(orderId);
} catch (ServiceException e) {
logger.error("订单处理失败,订单ID: {}", orderId, e);
throw new BusinessException("下单异常,请稍后重试", e);
}注意:
- 使用占位符 {} 避免字符串拼接开销(SLF4J 支持)
- 第三个参数是异常对象,不是字符串
- 若需包装异常再抛出,建议将原异常作为 cause 传入构造函数,保持堆栈可追溯
自定义日志格式确保堆栈可见
检查日志配置(如 logback.xml 或 log4j2.xml),确认 pattern 中包含 %ex(Logback)或 %throwable(Log4j2)等转换词:
- Logback 示例:
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%ex%n - Log4j2 示例:
%d{HH:mm:ss.SSS} [%t] %-5level %c{36} - %m%ex%n
缺了 %ex 或类似字段,即使代码传了异常,日志里也看不到堆栈。

















