java自定义异常不自动触发prometheus埋点,需在抛出前主动调用counter.increment()记录带标签的业务错误次数,或在全局异常处理器中统一埋点,并结合traceid实现指标与日志关联分析。

Java 自定义异常本身不直接触发 Prometheus 埋点,但你可以通过“在抛出自定义异常的关键路径上主动记录监控指标”,实现业务异常与可观测性的联动。核心思路是:把异常发生视为一个可度量的业务事件,用 Prometheus 的 Counter 或 Histogram 记录它,而不是依赖异常自动上报。
在自定义异常被抛出前记录 Counter
最常用也最推荐的方式:在真正 throw 异常的那一刻(或其上游统一处理点),递增一个带标签的计数器。这样能精确反映“某类业务异常发生了多少次”,且不干扰原有异常逻辑。
- 定义 Counter(建议用
Counter.builder()+register()):
.description("Total number of business errors")
.tag("type", "payment_timeout")
.tag("service", "order-service")
.register(Metrics.globalRegistry);
- 在抛出自定义异常前调用:
errorCounter.increment(); - 如果异常类型多样(如
InsufficientBalanceException、InventoryLockFailException),建议为每种类型创建独立 tag 值,或用tag("exception", e.getClass().getSimpleName())动态打标
在全局异常处理器中统一埋点
使用 @ControllerAdvice 或 Spring Boot 的 ErrorWebExceptionHandler,集中捕获自定义异常并记录指标。这种方式避免重复写埋点代码,适合 Web 层。
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
- 示例片段(Spring MVC):
public ResponseEntity> handleInventoryLockFail(InventoryLockFailException e) {
inventoryLockErrorCounter.tag("reason", e.getReason()).increment();
return ResponseEntity.status(409).body("库存锁定失败");
}
- 注意:不要在 handler 里吞掉异常却不记录——这会让监控丢失上下文;也不建议仅靠 HTTP 状态码反推异常类型(比如 409 不一定全是库存问题)
结合日志与指标做关联分析
Prometheus 擅长聚合趋势,但查根因需要日志。建议让自定义异常构造时生成唯一 trace ID(或复用 MDC 中的 traceId),并在埋点时作为 label 或额外字段(需配合 Pushgateway 或日志采集器)。
- 例如:
errorCounter.tag("trace_id", MDC.get("traceId")).increment(); - 这样在 Grafana 中点击某个突增的异常曲线,就能下钻到对应时间窗口的 ELK 日志,快速定位参数、用户 ID、订单号等细节
- 避免把敏感信息(如手机号、身份证)打入 Prometheus label,label 值应精简、离散、低基数
慎用 Histogram 记录异常延迟(仅限特定场景)
如果你关注的是“某类异常是否集中在慢请求中发生”,可以搭配 Timer 或 Histogram,在异常路径上记录耗时。但注意:这不是记录异常本身,而是记录“导致异常的那一次调用花了多久”。
- 适用场景:排查“超时类异常是否随下游响应变慢而激增”
- 不适用场景:普通校验失败(如参数非法)、瞬时逻辑错误——它们和耗时无关,强行打 Histogram 会污染分位数统计
- 推荐方式:
timer.record(() -> { /* 可能抛异常的业务逻辑 */ });,并在 catch 块中单独计数
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










