业务指标不出现是因为指标注册到默认 registry 而 handler 使用自定义 registry,导致两者不一致;需确保 registry 实例、指标创建、注册调用、handler 初始化四者使用同一 registry 并按序执行。

直接用 promhttp.Handler() 暴露 /metrics 端点,但业务指标不出现?大概率是指标没注册到 handler 对应的 registry,或注册到了默认 registry 却用了自定义 handler。
为什么 /metrics 返回空或只有 go_* 指标
现象:HTTP 访问 /metrics 返回 200,内容里只有 go_goroutines、process_cpu_seconds_total 这类内置指标,你的 my_app_requests_total 完全不见。
- 根本原因:你调用了
prometheus.MustRegister()(注册到默认 registry),但 handler 用的是promhttp.HandlerFor(reg, ...)(只读取reg里的指标)——两者 registry 不一致 - 另一个常见原因:指标变量定义在包级,但
MustRegister()调用被漏掉,或写在了init()里而初始化顺序不可控 - 别依赖 “自动注册”:Go client 不会自动发现你声明的
NewCounterVec变量,必须显式reg.MustRegister(...)
如何正确注册并绑定自定义指标
核心原则:registry 实例、指标创建、注册调用、handler 初始化,四者必须用同一个 registry 实例,且顺序不能乱。
- 先创建 registry:
reg := prometheus.NewRegistry() - 再创建指标,并立即注册:
counter := prometheus.NewCounterVec(...); reg.MustRegister(counter)(注意是reg.MustRegister,不是prometheus.MustRegister) - 最后挂路由:
http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{})) - 如果要用 Go 运行时指标,手动加:
reg.MustRegister(prometheus.NewGoCollector()),而不是靠默认行为
Vec 类型打点时 panic: expected 2 label values but got 1
定义了 requestsTotal := prometheus.NewCounterVec(..., []string{"method", "status"}),但调用 requestsTotal.WithLabelValues("GET") 就 panic——标签数量必须严格匹配定义时的 label 名称数组长度。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 必须传满所有 label 值:
requestsTotal.WithLabelValues("GET", "200").Inc() - 避免在循环中反复调用
WithLabelValues():它内部查 map,高频调用有开销;应缓存结果,如get200 := requestsTotal.WithLabelValues("GET", "200"),后续直接get200.Inc() - label 值来自 URL 或用户输入时,必须过滤或哈希,比如把
/user/12345归一为/user/:id,否则 label 基数爆炸,Prometheus 内存会飙升
本地 curl /metrics 拿不到数据,先检查这三处
不是代码逻辑问题,而是 HTTP 层暴露失败。最常卡在这几个地方:
- 没调用
http.ListenAndServe(),或监听端口被占用(如:9100已被其他进程占着) - 用了自定义
http.ServeMux却没传给http.Server,比如写了mux := http.NewServeMux(); mux.Handle(...),但启动时仍用http.ListenAndServe(":9100", nil)—— 此时nil表示用默认 multiplexer,你的mux根本没生效 - 指标注册发生在
http.ListenAndServe()之后:Go 是顺序执行的,注册晚于 server 启动,首次抓取就错过
真正容易被忽略的是 registry 生命周期和 handler 绑定时机——一旦用错 registry 实例,指标就彻底“隐身”,连日志都不会报错,只能靠逐行比对注册与 handler 是否指向同一变量。

















