logback 中需配置 %ex{full} 才能完整打印异常链:在 logback.xml 的 中使用 %ex{full} 可递归展开所有 getcause(),避免手动抛异常时未传入原 throwable 导致断链,验证方法是触发多层嵌套异常并检查日志中是否出现多个“caused by”。

Logback 默认只打印异常的最外层堆栈,如果想完整显示整个异常链(即 Cause 链,包括 getCause() 逐层嵌套的所有异常),关键在于正确配置 %ex 或 %throwable 转换词,并确保日志级别足够、异常被正确抛出和捕获。
使用 %ex{full} 显式启用全量异常链
在 logback.xml 的 <pattern></pattern> 中,用 %ex{full} 替代默认的 %ex 或 %throwable。这是最直接有效的方式:
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%ex{full}%n</pattern>其中 {full} 表示递归展开所有 cause,直到 cause == null,且每层都带完整堆栈。不加参数时(如 %ex)默认只展开一层 cause,容易遗漏深层根因。
避免手动“吞掉”异常链
常见错误是捕获异常后新建一个新异常但未传入原异常作为 cause,导致链断裂。务必使用带 Throwable 参数的构造函数:
- ✅ 正确(保留链):
throw new ServiceException("业务失败", e); - ❌ 错误(断链):
throw new ServiceException("业务失败");(丢失原始堆栈) - ⚠️ 注意:Spring 等框架的某些包装逻辑(如
new RuntimeException(msg))也会隐式断链,需检查中间层是否主动丢弃了 cause
验证配置是否生效的简单方法
写一段会触发多层嵌套异常的测试代码,例如:
try {
methodA();
} catch (Exception e) {
logger.error("操作失败", e); // 必须把异常对象作为参数传入
}其中 methodA → methodB → methodC 层层抛出不同异常(如 IOException 包装为 RuntimeException 再包装为 ServiceException)。运行后查看日志输出是否包含类似:
Caused by: java.io.IOException: 模拟IO异常 at ... ... 1 more Caused by: java.lang.RuntimeException: 包装IO异常 at ... ... 1 more Caused by: com.example.ServiceException: 业务层异常 at ...
出现多个 “Caused by” 即表示异常链已完整打印。
进阶:自定义异常转换器(按需)
若需定制格式(如加前缀、过滤敏感字段、限制深度),可实现 IThrowableRenderer 并注册到 logback.xml:
- 编写类继承
ch.qos.logback.core.pattern.ThrowableHandlingConverter或实现接口 - 在
logback.xml中通过<throwablerenderer class="com.example.MyFullRenderer"></throwablerenderer>声明 - 通常不必要,
%ex{full}已覆盖绝大多数场景
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











