Java自定义异常需显式集成日志与告警:在抛出/捕获/全局处理时调用SLF4J等框架记录ERROR/WARN日志,结合MDC、业务码、alertable标识及getAlertKey()方法支持分级告警;告警通过ELK/Prometheus规则绑定alert_key或指标实现,禁在异常构造器或toString中直接打日志或硬编码告警逻辑。

Java 自定义异常本身不自动记录日志或触发告警,需在抛出、捕获或全局处理时,显式调用日志框架(如 SLF4J + Logback / Log4j2)并指定日志级别(如 ERROR、WARN),同时可结合 MDC、自定义字段或告警系统(如 Prometheus + Alertmanager、ELK + Watcher)实现独立告警分级。
在自定义异常类中预设日志上下文
不推荐在异常构造器里直接打日志(违反单一职责),但可支持携带关键元数据,便于后续统一记录:
- 定义业务码、错误分类(如 PAY_FAILED、AUTH_TIMEOUT)、是否需告警(isAlertable = true)
- 重写 getLocalizedMessage() 或新增 getAlertKey() 方法,返回唯一告警标识(如 "ALERT_PAY_RETRY_EXCEEDED")
- 示例片段:
public class PaymentException extends RuntimeException {
private final String bizCode;
private final boolean alertable;
public PaymentException(String msg, String bizCode, boolean alertable) {
super(msg);
this.bizCode = bizCode;
this.alertable = alertable;
}
public String getAlertKey() { return "ALERT_" + bizCode.toUpperCase(); }
}
在 catch 块或全局异常处理器中按需打日志
真正控制日志级别和内容的地方,应结合异常类型、业务场景、是否可恢复来决策:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 对明确需人工介入的失败(如支付扣款成功但回调超时),用 logger.error(),并填充 MDC(如 MDC.put("traceId", tid)、MDC.put("orderId", oid))
- 对预期中的临时性异常(如第三方接口限流返回 429),用 logger.warn(),避免刷屏,但保留可追溯性
- 避免在 throw new XxxException(...) 后立刻 log,易造成重复日志;建议只在最终处理点(如 ControllerAdvice 或 AOP 切面)记录一次
对接告警系统实现“独立级别”
日志级别只是基础,真要实现告警分级,需额外机制:
立即学习“Java免费学习笔记(深入)”;
- 日志采集侧过滤:Logback 中用 AsyncAppender + ThresholdFilter 区分 ERROR/WARN 日志输出到不同文件或 Kafka Topic
- 告警规则绑定:在 ELK 中用 alert_key: "ALERT_PAY_FAILED" 字段 + 频次阈值(如 5 分钟超 10 次)触发企业微信告警;在 Prometheus 中,用 Micrometer 记录 exception_occurred_total{type="PaymentException",alertable="true"} 并配置 Alertmanager 规则
- 降级开关联动:在捕获到高频 PaymentException 时,自动触发熔断器状态变更,并同步推送 SEVERITY_HIGH 级别告警
不建议的做法
这些方式会削弱可维护性或引入风险:
- 在自定义异常的 toString() 里写 System.err.println() —— 绕过日志框架,无法统一管理格式、异步、滚动策略
- 每个 catch 都写 logger.error("xxx", e) 而不区分场景 —— 导致 WARN 级异常也被推为 ERROR 告警,产生噪音
- 把告警逻辑硬编码进异常类(如调用 DingTalk SDK)—— 违反关注点分离,测试困难,且无法动态调整告警渠道

















