核心是使用logger.error("msg", e)并配置%ex,让日志框架原生输出完整堆栈、cause链和suppressed异常;禁用e.printstacktrace()和字符串拼接,避免丢失调用层级与上下文。

Java 异常捕获后要规范打印完整错误堆栈,核心是让日志框架“原生接管”异常对象,而不是把它转成字符串拼进日志消息里。只要写法和配置都到位,Logback、Log4j2 或 SLF4J 绑定的其他实现都能自动展开完整的调用链、嵌套 cause 和 suppressed 异常。
用对日志方法:异常对象必须作为最后一个参数传入
SLF4J 提供了带 Throwable 参数的重载方法(如 error(String, Throwable)),框架会识别并自动展开堆栈。关键规则是:
- 消息字符串中使用占位符(如
{}),异常对象单独作为最后一个参数传入 - 不能把异常塞进字符串里——
e.toString()、e.getMessage()或Arrays.toString(e.getStackTrace())都只输出片段,丢掉调用层级、cause 链和格式化缩进 - 示例:
✅logger.error("读取配置失败,key={}", key, e);
❌logger.error("读取配置失败,key=" + key + ", error=" + e);
❌logger.error("读取配置失败,key={}", key, e.getMessage());
检查 logback.xml 的 pattern 是否启用 %ex 或 %xEx
即使代码传对了异常,如果日志模板没声明输出异常字段,堆栈就不会出现。确保 <encoder></encoder> 中的 <pattern></pattern> 包含以下之一:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
%ex:标准完整堆栈(最常用) -
%xEx:递归展开所有 cause(适合 Spring、Feign 等多层包装场景) -
%throwable:语义等价于%ex,可读性更强 - 避免仅写
%msg—— 它只输出日志消息,不包含异常内容 - 若需控制深度(比如防超长日志),可用
%ex{10},但默认不加数字即全量输出
别吞异常,也别手动包装丢掉 cause
捕获后不做处理或错误重抛,会导致原始堆栈丢失:
- ❌ 静默吞掉:
catch (IOException e) { logger.error("文件操作失败"); }→ 没传异常对象,堆栈彻底消失 - ✅ 正确记录+传递:
catch (IOException e) { logger.error("用户头像上传失败", e); } - ✅ 转换异常类型时保留 cause:
throw new ServiceException("图片服务不可用", e);→ 新异常构造器带 cause,Logback 仍能递归打印原始堆栈 - ⚠️ 避免
e.initCause(...)或new XxxException().initCause(e)—— 构造阶段应直接用带 cause 的构造器
生产环境禁用 printStackTrace()
e.printStackTrace() 只输出到 System.err,无法被日志系统收集、过滤、滚动或关联 traceId,线上等于“黑盒报错”:
- 它绕过日志级别、MDC 上下文(如
MDC.put("traceId", id))、异步 appender 性能优化 - 多线程下输出混杂,Android 或容器环境中还可能被截断或丢弃
- 真需要字符串形式(如上报、调试响应),用
StringWriter + PrintWriter封装再交由 logger 输出,而非直接调用 - 本地调试可用,但上线前必须全部替换为
logger.error(..., e)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










