Prometheus只能看到go_*等运行时指标,因业务指标未调用prometheus.MustRegister()注册;注册必须在http.ListenAndServe()前完成,且需与promhttp.Handler()使用同一注册器。

直接暴露 /metrics 端点但没注册指标,Prometheus 就只能看到 go_* 和 process_* 这类运行时指标,你的业务指标压根不会出现——这不是配置漏了,是根本没“告诉” Prometheus 它该收集什么。
为什么 /metrics 返回 200 却没有业务指标?
最常见原因:只挂了 handler,没调 prometheus.MustRegister()。你定义的 http_requests_total 只是个 Go 变量,不注册就等于不存在。
- 注册必须在
http.ListenAndServe()之前完成;写在 handler 函数里、中间件里或 goroutine 里都无效 - 用
promauto.NewCounterVec()虽自动注册,但多个包重复初始化同名指标会 panic,中大型项目建议统一用prometheus.NewRegistry()+ 手动reg.MustRegister() - 若需运行时指标(如
go_goroutines),要显式注册:reg.MustRegister(prometheus.NewGoCollector()),不能依赖默认行为
CounterVec 和 Histogram 怎么选、怎么配?
HTTP 请求成功率和耗时必须拆开处理,混用会导致 P99 查不准、rate() 失效。
-
http_requests_total必须是CounterVec,标签用method、path、status;算错误率直接写rate(http_requests_total{status=~"4..|5.."}[5m]) / rate(http_requests_total[5m]) -
http_request_duration_seconds必须是Histogram(不是Summary),因为Summary不支持rate()和跨时间窗口聚合 - Buckets 别用默认值;SLA 是 200ms,就设
[]float64{0.05, 0.1, 0.2, 0.5};把status塞进 Histogram 标签是反模式——它无法做多维聚合统计
标签设计踩哪些坑会让 Prometheus 崩掉?
高基数标签(比如 user_id、trace_id、未归一化的 /order/12345)会让时间序列数量爆炸,内存和查询响应双双失控。
立即学习“go语言免费学习笔记(深入)”;
- 路径必须归一化:
/order/12345→/order/{id},否则每个 ID 都生成独立序列 - 禁止直接用业务 ID 打标;改用分类,比如
error_type="timeout"、error_type="db_error" - 标签名全小写+下划线:
tenant_id合法,TenantID或tenant-id会引发解析问题 -
WithLabelValues()参数顺序必须和NewCounterVec(..., []string{"a", "b", "c"})定义顺序严格一致,错一位就静默丢数
如何避免生产环境暴露所有指标?
直接用 promhttp.Handler() 会绑定全局注册器,把 SDK 自带的 go_*、process_* 全吐出来——这在生产环境属于信息泄露风险。
- 显式创建独立注册器:
reg := prometheus.NewRegistry() - 只注册你要暴露的指标:
reg.MustRegister(httpRequestsTotal),别碰prometheus.MustRegister() - 启动 handler 时传入该注册器:
http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{})) - 调试时用
.WithLabelValues("/api/user", "GET", "200").Inc(),比.With(map[string]string{})更快、更安全,且能提前捕获空标签 panic
真正难的不是写几行注册代码,而是指标命名是否一致、标签是否可聚合、Buckets 是否贴合 SLA、注册时机是否在 server 启动前——这些地方错一个,查监控时就少一条路。


















