You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Micrometer的@Counted注解能否忽略指定标签,仅按错误码统计指标?

解决Spring Micrometer @Counted按指定标签聚合的问题

先直接给结论:原生的@Counted注解没办法直接实现你要的效果——因为Micrometer里的指标标签是用来区分不同时间序列的,每个error_code+unique_id的组合都会被当成独立的指标,所以每个unique_id都会单独计数,不会自动合并。

先理清楚你的需求:你现在的注解同时加了两个标签,所以每个不同的unique_id都会生成一条独立的指标。而你想要的是同一个error_code下,不管unique_id是什么,计数都累加。下面给你几个可行的解决方案:

方案1:移除unique_id标签(最简单直接)

如果你的核心需求就是按error_code聚合计数,unique_id只是用来追踪单个请求而非聚合维度,那直接修改@Counted注解,去掉unique_id的标签配置就好:

@Counted(name = "my_metric", labels = {"error_code:$0"})

这样不管传入什么unique_id,指标都会按error_code来聚合,最终你会得到:

my_metric_total{error_code="test-1"} 2.0

要是需要记录unique_id的信息,用日志来记录就够了——指标标签应该用来做低基数的聚合维度,像unique_id这种高基数的值会导致指标数量爆炸,这是监控领域的大忌,Micrometer本身也不推荐这么用。

方案2:自定义MeterFilter合并标签(适合需要统一处理指标的场景)

如果你必须在代码里保留unique_id的标签配置,但又想让指标最终按error_code聚合,可以通过自定义MeterFilter来拦截并修改指标:

创建一个自定义的过滤器组件:

@Component
public class UniqueIdAggregationFilter implements MeterFilter {
    @Override
    public Meter.Id map(Meter.Id id) {
        // 只处理我们关心的my_metric指标
        if ("my_metric_total".equals(id.getName())) {
            // 过滤掉unique_id标签,只保留error_code
            List<Tag> filteredTags = id.getTags().stream()
                    .filter(tag -> !"unique_id".equals(tag.getKey()))
                    .collect(Collectors.toList());
            return id.withTags(filteredTags);
        }
        // 其他指标保持原样
        return id;
    }
}

这个过滤器会在指标注册到MeterRegistry时移除unique_id标签,这样所有相同error_code的请求都会被合并到同一个指标里计数累加。不过这样最终的指标里就看不到unique_id了,和方案1的效果一致。

方案3:自定义CountedAspect(最灵活的控制)

如果你的场景更复杂,比如某些情况下需要保留unique_id标签,某些情况下需要聚合,那可以自定义CountedAspect来覆盖默认的计数逻辑:

@Aspect
@Component
public class CustomCountedAspect extends CountedAspect {
    public CustomCountedAspect(MeterRegistry meterRegistry) {
        super(meterRegistry);
    }

    @Override
    protected void increment(Counted counted, String[] args) {
        // 只取第一个参数作为error_code,忽略第二个unique_id参数
        String errorCode = args[0];
        // 创建只带error_code标签的计数器并累加
        Counter counter = Counter.builder(counted.name())
                .tag("error_code", errorCode)
                .register(getMeterRegistry());
        counter.increment();
    }
}

这样不管你原来的@Counted注解里怎么配置unique_id标签,自定义的切面都会忽略它,只按error_code来创建计数器并累加计数。

最后提个醒

一定要注意:高基数标签(比如每个请求都不一样的unique_id)会严重增加Prometheus的存储和查询压力,甚至可能导致监控系统崩溃。所以除非有特别明确的需求,否则别把这类高基数的值作为指标标签,用日志来追踪单个请求的唯一ID才是更合理的做法。

内容的提问来源于stack exchange,提问作者Estarossa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 15:28:13