业务异常应记warn日志且不输出堆栈,仅记录关键上下文;error日志仅用于真正故障,需按异常类型分流处理,并通过日志配置裁剪或代码剥离包装异常来避免栈污染。

业务异常不该打ERROR日志,更不该输出完整堆栈——它不是故障,只是流程中的正常分支。关键在“区分类型”和“控制日志行为”。
只记录简明信息,不打印堆栈
对自定义的业务异常(如 BusinessException、InsufficientBalanceException),全局处理器中应避免调用 log.error("msg", e) 这类带异常对象的写法。它会强制输出全量栈,污染日志。
- 改用
log.warn("业务异常 -> 路径: {}, 错误: {}", uri, e.getMessage()),只记关键上下文和提示语 - 不传异常对象,就不会触发 Logback/Log4j2 的栈展开逻辑
- 前端拿到的是明确提示(如“库存不足”),后端日志里也干净可读
按异常类型分流处理
在 @ControllerAdvice 中为不同异常写独立的 @ExceptionHandler 方法,确保业务异常走“轻日志路径”:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
@ExceptionHandler(BusinessException.class):只 warn + 返回友好结果 -
@ExceptionHandler(SQLException.class)或@ExceptionHandler(NullPointerException.class):才用log.error("xxx", e)记完整栈 -
@ExceptionHandler(Exception.class)放在最后兜底,但也要判断是否为业务异常子类,避免误打栈
借助日志框架的栈裁剪能力
即使不小心传了异常,在日志配置里也能抑制冗余栈:
- Logback 中使用
%ex{short}替代%ex{full},只保留最外层异常 + 第一个业务类帧 - Log4j2 可配
%throwable{short}或自定义ThrowablePatternConverter - 若用 Sentry/ELK,检查其 stack trace fingerprinting 规则,避免把业务异常当成崩溃上报
代码层面主动剥离包装,避免栈膨胀
有些业务异常会被 CompletionException、ExecutionException 包裹(尤其在异步场景)。不要直接记 e 的栈,先提取根因:
- 用工具方法获取真实异常:
getRootCause(e) - 再判断:如果是你定义的
BusinessException,仍走 warn 路径;如果是SQLException,才记 error + 栈 - 这样既保排查线索,又不把“用户输错手机号”和“数据库连不上”混为一谈










