必须用 CounterVec 等向量类型实现带标签计数器,标签在创建时固定且顺序严格匹配,需避免路径爆炸、重复注册和维度滥用。

用 prometheus.NewCounterVec 创建带标签的计数器
Go 里不能直接给原始 prometheus.Counter 加标签——它只支持无维度的单值累加。真要区分接口、状态码、方法等,必须用向量类型,比如 CounterVec、GaugeVec 或 HistogramVec。
常见错误是先声明一个普通 Counter,再试图在 Inc() 时传标签,结果编译报错:too many arguments in call to counter.Inc。
- 标签定义在创建时固定,不可动态增减,例如
[]string{"method", "path", "status"} - 标签名必须是合法标识符(不能含
-、/、空格),但值可以是任意字符串(如/api/v1/users) - 每次
WithLabelValues("GET", "/users", "200").Inc()才真正写入一个具体时间序列 - 别在热路径里反复调用
WithLabelValues:它内部有 map 查找,虽快但非零开销;建议把常用组合缓存为局部变量
标签值别硬编码路径或用户输入
HTTP 接口指标中,把完整请求路径(如 /users/123)当 path 标签值,会导致时间序列爆炸——每个 ID 都生成新序列,Prometheus 内存和查询压力飙升。
正确做法是做路由模板化:用 Gin 的 c.FullPath()、Echo 的 c.Request().URL.Path 替换动态段,或手动正则归一化。
立即学习“go语言免费学习笔记(深入)”;
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- Gin 示例:
path := strings.ReplaceAll(c.FullPath(), c.Param("id"), ":id") - 避免用
c.Request().URL.Path直接取值,它含查询参数且未标准化(如/a?x=1&y=2) - 标签值长度尽量控制在 100 字符内;超长值不会报错,但会拖慢存储和聚合
- 空值或非法字符(如
\x00)会被 Prometheus 客户端静默丢弃,导致指标“消失”,建议提前strings.TrimSpace并校验
WithLabelValues 参数顺序必须严格匹配定义顺序
标签定义顺序和调用 WithLabelValues 时传参顺序不一致,会导致 panic:panic: inconsistent label cardinality。这不是运行时报错,而是客户端在首次调用时校验失败并 panic。
比如定义时是 []string{"status", "method", "path"},但调用写成 .WithLabelValues("GET", "200", "/login"),就会崩。
- IDE 无法静态检查这个顺序,靠人眼对齐,容易出错;建议把标签名常量化,比如
const ( LabelMethod = "method"; LabelPath = "path" ),并在注释里写明顺序 - 如果标签多于 4 个,考虑拆成多个指标(如按业务域分
api_auth_requests_total、api_user_requests_total),比堆一堆标签更易查、更稳定 - 不要为了“省事”用
With方法传map[string]string——它不校验键是否全量存在,漏掉一个标签名就返回 nil 指针,后续Inc()panic
HTTP 中间件里注册指标要防重复注册
多个中间件或多个路由组都调用同一段指标初始化代码(比如 prometheus.MustRegister(counter)),会导致 duplicate metrics collector registration attempted panic。
根本原因是 Prometheus 默认 registry 是全局单例,且不允许多次注册同名指标。
- 把指标声明和注册拆开:变量定义放包级,
init()或main()里只注册一次 - 不要在 handler 函数里
prometheus.NewCounterVec(...).MustRegister()——每次请求都试注册,必炸 - 若需模块化(如 auth 包、user 包各自定义指标),用自定义 registry:
reg := prometheus.NewRegistry(),再传给http.Handler,避免污染默认 registry - 测试时用
prometheus.NewPedanticRegistry(),它会在注册前做更严校验,提前暴露命名冲突
group by 聚合、是否有足够基数支撑下钻分析。否则只是给 Prometheus 增加负担。

















