必须显式调用prometheus.mustregister()注册业务指标,否则/metrics仅返回go_*等运行时指标;包级变量定义+init()或main()开头注册,避免重复panic或静默丢失。

直接暴露 /metrics 端点但看不到业务指标?不是 Prometheus 配置问题,而是你的指标根本没注册进采集器——90% 的失败卡在 prometheus.MustRegister() 漏掉或时机不对。
为什么 curl localhost:8080/metrics 有数据但没你的业务指标
默认的 promhttp.Handler() 只暴露 go_*、process_* 这类运行时指标。你定义的 httpReqCounter 如果没调用 prometheus.MustRegister(),它就不存在于默认注册器里。
- 运行时指标(goroutine 数、内存分配等)自动注册;业务指标必须显式注册,且只允许一次
- 常见错误:把
prometheus.NewCounterVec()写在 handler 函数里,每次请求都新建+注册 → 启动 panic 或指标静默丢失 - 正确做法:声明为包级变量 + 在
init()或main()开头注册
http.ListenAndServe() 传 promhttp.Handler() 编译报错
错误提示类似 cannot use promhttp.Handler() (value of type http.Handler) as type func(http.ResponseWriter, *http.Request),是因为 http.ListenAndServe() 第二个参数接受 nil 或函数类型,而 promhttp.Handler() 返回的是 http.Handler 接口实例。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
- 安全写法:
http.Handle("/metrics", promhttp.Handler())+http.ListenAndServe(":8080", nil) - 更推荐新建独立 mux:
mux := http.NewServeMux(); mux.Handle("/metrics", promhttp.Handler()); http.ListenAndServe(":8080", mux),避免污染http.DefaultServeMux - 若用 Gin/Echo,必须包装:
gin.WrapH(promhttp.Handler())或echo.WrapHandler(promhttp.Handler())
用 CounterVec 打状态码维度时为啥指标爆炸
直接用 r.StatusCode 当 label 值,会导致每个新状态码(比如 429123)都生成一个新时间序列,Prometheus server 内存和查询性能迅速崩坏。
- label 值必须是低基数、预定义集合,例如
"200"、"404"、"500"、"other" - 别用
strconv.Itoa(r.StatusCode)直接转,而是用switch映射常见码,非标统一归入"other" - 路径、用户 ID、UUID 绝对不能进 label —— 这是 cardinality problem 的高发区
活跃连接数该用 Counter 还是 Gauge
用 Counter 统计“当前在线人数”或 WebSocket 连接数,等于埋雷:它只能增不能减,goroutine 退出后指标永远卡在高位,监控完全失真。
- 活跃连接、内存用量、线程数等瞬时值,必须用
prometheus.NewGauge() - 每个 goroutine 启动时
.Inc(),退出时.Dec()—— 忘记Dec()就等于泄漏指标 - 如果要用
GaugeFunc包装runtime.NumGoroutine(),注意它不保证并发安全,采样时可能触发锁竞争
最易被忽略的点:监听地址绑定。Go 默认用 ":8080" 启动时监听的是 localhost:8080(loopback),容器或远程 Prometheus 抓不到——得改成 "0.0.0.0:8080"。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










