/metrics返回空或无自定义指标,根本原因是指标未注册且未打点:必须用prometheus.mustregister()显式注册countervec等指标,并调用.inc()或.observe()首次触发,否则不会出现在/metrics中。

直接写 promhttp.Handler() 暴露 /metrics 端点,业务指标默认不会出现——它只返回已注册且被触发过的指标,而你定义的 CounterVec、HistogramVec 必须手动注册、手动打点,缺一不可。
为什么 /metrics 返回空或看不到自定义指标
根本不是代码没跑,是指标没“活过来”:既没注册进注册器,也没被调用过 .Inc() 或 .Observe()。
-
prometheus.NewCounterVec()只是创建一个 Go 对象,必须显式调用prometheus.MustRegister(yourMetric)才能进默认注册表;若用了独立prometheus.NewRegistry(),就得配promhttp.HandlerFor(reg, ...) - Counter 类型不报零值:刚启动时
http_requests_total在/metrics里就是空的,正常。只有某次请求真正执行了httpRequestsTotal.WithLabelValues("GET", "/api/v1", "200").Inc(),它才会首次出现 - label 值不能为空字符串或
nil;声明了三个 label(如[]string{"method", "endpoint", "status"}),调用时就必须传三个非空字符串,顺序、数量、类型全得对,错一个就静默丢失——/metrics里查不到,也无 panic 或日志
如何正确暴露 /metrics 端点且不被业务拖垮
别把监控端点塞进业务 HTTP Server 里,否则业务 panic 或中间件改响应头会直接让监控失效。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
- 起一个独立
http.Server,监听如:9091,绑定空地址(即":9091",不是"127.0.0.1:9091"),确保容器外或宿主机上的 Prometheus 能访问到 - handler 必须直挂
promhttp.Handler()或promhttp.HandlerFor(reg, ...),禁用任何中间件拦截——它需要原生Content-Type: text/plain; version=0.0.4,加个gzip或Content-Type: text/html都会导致 Prometheus 抓取失败 - 务必注册运行时指标:
prometheus.MustRegister(prometheus.NewGoCollector()),否则go_goroutines、go_memstats_alloc_bytes这类基础指标压根不会出现
HTTP 请求埋点该用什么指标类型和 label 设计
用错类型或 label 维度爆炸,等于白埋——查不到数据、存储崩、查询慢都是后遗症。
- 请求总数用
CounterVec,响应时间必须用HistogramVec:前者支持rate(),后者才能算 P95/P99;别用Gauge记总请求数,也别用Counter记耗时 - 路径 label 别用
r.URL.Path(如/user/123),要提取路由模板(Gin 用c.FullPath()得到/user/:id);状态码别直接塞r.StatusCode,先映射成"200"/"404"/"5xx"等有限枚举值 - bucket 设置不能硬套
prometheus.DefBuckets:毫秒级 API 的 P99 是 300ms,就该用[]float64{0.05, 0.1, 0.2, 0.3, 0.5, 1.0},否则前几个 bucket 永远为空,_bucket序列毫无意义
多包、热重载或插件场景下怎么避免 duplicate metrics collector registration attempted
panic 不是偶然,是多个包都试图注册同名指标——尤其在测试或模块化服务中高频发生。
- 禁用
promauto.NewCounterVec()跨包使用:它内部依赖全局注册器,两个包都初始化http_requests_total就直接 panic - 中大型项目统一用
prometheus.NewRegistry()+prometheus.NewCounterVec(...)+reg.MustRegister(),把注册控制权收归main包启动阶段 - 所有指标对象必须在
init()或main()开头一次性注册完毕;绝不能在 handler 里 new 指标再注册,每次请求都会触发重复注册 panic
最常被跳过的其实是 label 合法性检查和 bucket 实际分布匹配——名字含短横线、值来自用户输入、桶边界远超真实延迟,这些细节不卡在开发期,就会卡在告警查不到数据的时候。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










