go服务暴露prometheus监控指标必须显式注册promhttp.handler()到/metrics路由,否则返回404或空响应;自定义业务指标需在启动时调用prometheus.mustregister()注册,且不可重复注册,计数器应选countervec按标签分类统计,直方图需按实际延迟分布配置桶区间。

注册HTTP handler时别漏掉promhttp.Handler()
Go服务暴露监控指标,核心就是把promhttp.Handler()挂到某个HTTP路由上。最常见错误是只调用prometheus.MustRegister()却没暴露端点,导致curl /metrics返回404或空响应。
正确做法是在启动HTTP server前注册handler:
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8080", nil)
注意:promhttp.Handler()返回的是标准http.Handler,可直接传给http.Handle或集成进Gin/Echo等框架的中间件。若用Gin,写法是r.GET("/metrics", gin.WrapH(promhttp.Handler()))。
自定义指标要显式调用prometheus.MustRegister()
内置的Go运行时指标(如go_goroutines)默认已注册,但业务指标(比如请求计数、耗时直方图)必须手动注册,否则不会出现在/metrics输出里。
典型错误:声明了prometheus.NewCounterVec但忘记MustRegister,结果指标始终为0且无报错提示。
- 计数器示例:
reqCount := prometheus.NewCounterVec(prometheus.CounterOpts{Name: "http_requests_total"}, []string{"method", "code"})→ 必须跟prometheus.MustRegister(reqCount) - 直方图注意桶区间:默认
prometheus.DefBuckets可能不匹配你的API延迟分布,高频接口建议用[]float64{0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5} - 避免在goroutine里重复注册同名指标,会panic:“duplicate metrics collector registration attempted”
HTTP中间件中记录指标时小心ResponseWriter包装
想统计HTTP请求的status code和latency,不能直接用原生http.ResponseWriter,得用wrapper捕获状态码和写入时间。常见坑是忘了包装response writer,导致code维度永远是0或200。
推荐用promhttp.InstrumentHandlerDuration和promhttp.InstrumentHandlerCounter这类封装好的中间件,它们自动处理writer包装和指标更新:
handler := promhttp.InstrumentHandlerDuration(
httpRequestsDuration,
promhttp.InstrumentHandlerCounter(
httpRequestsTotal,
http.HandlerFunc(yourHandler),
),
)
http.Handle("/", handler)
如果自己实现wrapper,关键点是重写WriteHeader(int)方法,并确保在Write([]byte)前已记录状态码——否则Header().Get("Content-Type")可能为空,但更致命的是status未被捕获。
生产环境务必关闭prometheus.UnregisterAll()调用
本地调试时有人习惯在main函数开头加prometheus.UnregisterAll()清空所有指标,这在多实例部署或热更新场景下会导致指标丢失、Prometheus抓取失败(返回空内容或text/plain格式错误)。
真正需要清理指标的场景极少,绝大多数情况应让指标注册一次后长期存在。如果确实要动态注册/注销(比如插件式模块),必须用prometheus.Register()配合prometheus.Unregister()操作具体collector,而非全局清空。
另外,promhttp.Handler()本身是线程安全的,高并发下无需额外锁,但自定义collector里的Desc和Collect()方法必须保证goroutine安全——比如用sync.Mutex保护内部map计数。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











