Java异常链清洗需主动提取根因、截断代理层、结构化记录:用ExceptionUtils.getRootCause获取原始异常,正则截取堆栈首尾关键行,Logback配置ShortenedThrowableConverter排除org.springframework.cglib和com.sun.proxy,MDC分离上下文,日志模板显式控制字段内容。

Java中清洗异常链、剔除Spring代理层(如CGLIB、com.sun.proxy)的冗余堆栈,核心是不依赖默认printStackTrace,而是主动提取根因、截断无关调用、过滤特定包名。这能显著压缩日志体积,加快问题定位。
提取根本原因 + 截取关键堆栈
避免直接记录完整异常对象。优先获取最底层异常,并只保留真正有价值的堆栈行:
- 用 ExceptionUtils.getRootCause(e)(Apache Commons Lang)拿到原始异常,跳过层层包装
- 调用 ExceptionUtils.getStackTrace(e) 获取字符串堆栈,再用正则提取前3–5行(顶层异常声明)+ 后3–5行(实际出错位置),中间Spring AOP/CGLIB代理层直接跳过
- 示例正则截取逻辑:
stackLines.stream().limit(5).collect(...) + stackLines.stream().skip(stackLines.size()-5).collect(...)
自定义日志转换器过滤代理类
在Logback中通过 ThrowableProxyConverter 或自定义 PatternLayout 实现包名级过滤:
- 配置 logback-spring.xml 中的
<throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter"> - 添加
<exclude>org.springframework.cglib</exclude>和<exclude>com.sun.proxy</exclude> - 也可继承 ThrowableProxyConverter,重写
convert()方法,在遍历getStackTraceElement()时跳过含"$$EnhancerBySpringCGLIB"或"proxy$"的行
结构化记录 + 上下文剥离
把异常信息拆解为字段,而非拼成一整段message,避免代理层污染关键字段:
立即学习“Java免费学习笔记(深入)”;
- 用 MDC 单独注入
traceId、userId、interfaceName,不混在异常消息里 - 日志模板显式控制内容:
logger.error("db_query_fail|code={},msg={},root={}", e.getErrorCode(), StringUtils.substring(e.getMessage(), 0, 150), ExceptionUtils.getRootCause(e).getClass().getSimpleName()) - 对
e.getMessage()做长度限制,防止代理类全限定名撑爆字段


















