业务指标未出现在/metrics页面,根本原因是未调用prometheus.mustregister()显式注册,或注册时机错误(如在handler中注册);默认promhttp.handler()仅暴露defaultregisterer中的指标,而自定义counter/gauge需在init()或main()中提前注册才可见。

业务指标没出现在 /metrics 页面?不是 Prometheus 抓不到,而是你根本没注册上去——prometheus.MustRegister() 这一步漏了,或者注册时机错了。
为什么 promhttp.Handler() 返回的指标里没有你的 Counter 或 Gauge
默认的 promhttp.Handler() 只暴露 prometheus.DefaultRegisterer 里的指标。Go 运行时自带的 go_*、process_* 是自动注册的;但你自己 new 出来的 Counter 或 Gauge 不会自动进这个注册器。
- 常见错误:定义了
var orderCreatedCounter = prometheus.NewCounter(...),但没在init()或启动逻辑里调用prometheus.MustRegister(orderCreatedCounter) - 更隐蔽的问题:指标在包初始化阶段定义,但
init()函数执行顺序不可控,若依赖其他包先 init 再注册,可能被跳过 - 多注册器场景下(比如隔离测试/生产指标),用了
promhttp.Handler()却没传对应注册器,结果暴露的是空注册器
正确做法是显式构造并注册:
var orderCreatedCounter = prometheus.NewCounter(prometheus.CounterOpts{
Name: "order_created_total",
Help: "Total number of orders created",
})
func init() {
prometheus.MustRegister(orderCreatedCounter)
}
Counter 和 Gauge 到底该选哪个
关键看数据语义是否允许“减少”:Counter 是只增不减的累计值,Gauge 是可正可负的瞬时快照。
- 用
Counter记录事件总数:订单创建数、HTTP 请求次数、消息投递成功数;只能调Inc()或Add(n),传负数会 panic - 用
Gauge表示当前状态:活跃连接数、队列积压量、内存使用 MB;支持Inc()、Dec()、Set(x)、Add(delta),但不会自动归零,取消订单后得自己Dec() - 别用
Gauge.Set(1)模拟一次请求——这会让 PromQL 聚合失效(比如sum()就不是请求数)
命名也带信号:_total 后缀是 Counter 约定,_count 或 _size 更适合 Gauge。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
带 label 的指标必须提前声明所有 key
Label 名(key)不是运行时决定的,而是在 NewCounterVec 或 NewGaugeVec 初始化时就锁死的。一旦注册,不能再加新 label 名,也不能删。
- 错误写法:
counterVec.WithLabelValues("GET", "200").Inc()对应的 vec 初始化时只写了[]string{"method"},缺了"status"→ panic - 更危险的是动态拼 label 值:比如把用户邮箱当
user_emaillabel 值塞进去 → 高基数爆炸,Prometheus 内存暴涨甚至 OOM - label 值必须 sanitize:不能含空格、
/、大写字母、控制字符;推荐用固定枚举(如"prod"/"staging")或哈希脱敏后填入
安全写法示例:
var httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total HTTP requests",
},
[]string{"method", "status"}, // ← 所有 key 必须在这里一次性列全
)
func init() {
prometheus.MustRegister(httpRequestsTotal)
}
// 使用时确保值顺序和 key 顺序严格一致
httpRequestsTotal.WithLabelValues(r.Method, statusStr).Inc()
本地调试时 curl 不到指标?先查这三处
不是代码写错,往往是环境或路径细节卡住:
-
curl http://localhost:8080/metrics返回 404?检查是否用了http.Handle("/metrics", ...),而不是http.HandleFunc—— 后者不支持子路径匹配 - 返回 200 但 body 里只有
go_*?说明你的指标没注册,或注册到了另一个 registry,而 handler 挂的是默认注册器 - 指标值一直是 0?确认业务逻辑里真调了
.Inc()或.Set(),且调用路径没被 panic 或 early return 截断
最易忽略的一点:多个 goroutine 并发更新同一指标是安全的(底层用原子操作),但 label 组合一旦注册,就无法动态增删 key —— 这个限制在开发期就要想清楚维度设计,上线后再改就得停机重建指标。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










