直接 e.printstacktrace() 不适合生产环境,因它输出到 system.err、无法控制格式/级别/异步/归档,易拖慢服务或填满磁盘,且无业务上下文、可能被容器忽略;应使用 logger.error("msg", throwable) 并配合 mdc。

为什么直接 e.printStackTrace() 不适合生产环境
它把堆栈信息输出到 System.err,无法控制输出位置、格式、级别,也不支持异步写入或滚动归档。线上服务一旦高频抛异常,可能拖慢响应,甚至填满磁盘。
- 日志框架(如 Logback / Log4j2)能按级别过滤、按大小/时间切分文件、自动压缩旧日志
-
e.printStackTrace()无法携带业务上下文(如用户ID、请求ID),排查链路困难 - 部分容器或云平台会忽略
System.err输出,导致异常“静默丢失”
用 logger.error(String, Throwable) 记录异常最稳妥
这是 SLF4J + Logback/Log4j2 的标准用法,框架会自动把 Throwable 的完整堆栈附加在日志末尾,且保留消息结构化——方便 ELK 等工具提取字段。
logger.error("订单支付失败,orderNo={}", orderNo, e);
- 必须把
Throwable作为最后一个参数传入,不能拼在字符串里(否则只打印e.toString()) - 避免写成
logger.error("xxx" + e)或logger.error("xxx", e.getMessage()),会丢堆栈 - 如果用了 MDC(如
MDC.put("traceId", tid)),该异常日志会自动带上 traceId
哪些异常不该打 ERROR 级别
不是所有 Exception 都代表系统故障。过度标记 ERROR 会让真正的问题被淹没,也影响告警准确率。
- 用户输入校验失败(如
IllegalArgumentException)通常记WARN或INFO,加业务标识便于统计 - 第三方接口返回预期外的 HTTP 状态码(如 404、429),属于业务流一部分,不宜无差别记 ERROR
- 重试机制中的中间失败(如第一次调用超时,第二次成功),建议只在最终失败时记 ERROR
自定义异常类要重写 toString() 吗
不用。SLF4J 日志门面在记录 Throwable 时,依赖的是 Throwable.printStackTrace(PrintWriter),它不走 toString()。重点是确保构造时传入有意义的 message 和 cause。
立即学习“Java免费学习笔记(深入)”;
public class InventoryNotAvailableException extends RuntimeException {
public InventoryNotAvailableException(String sku, int requested) {
super(String.format("库存不足:sku=%s, requested=%d", sku, requested));
}
}
- 日志中看到的首行消息来自
super(message),不是toString() - 如果想额外带字段(如订单号),推荐在抛出前用 MDC 记录,而不是塞进 message 字符串
- 继承
RuntimeException还是Exception,和日志策略无关,只影响是否强制 try-catch
IOException,在读配置文件时发生是严重问题,在上传临时文件时发生可能只是客户端断连。得结合场景判断,而不是靠异常类型本身做决策。










