根本原因是指标未注册进prometheus默认注册表,即创建后未调用prometheus.mustregister();若使用自定义注册器,则需配套使用promhttp.handlerfor(),否则/metrics将不暴露该指标。

为什么/metrics返回空或看不到自定义指标
根本原因是指标没注册进 Prometheus 默认注册表。你写了 prometheus.NewCounterVec,但没调 prometheus.MustRegister(),它就只是个 Go 对象,不会出现在 /metrics 输出里。
- 必须在程序启动早期(比如
init()或main()开头)显式调用prometheus.MustRegister(yourMetric) - 如果用了自定义注册器(
reg := prometheus.NewRegistry()),就得用promhttp.HandlerFor(reg, ...),而不是默认的promhttp.Handler() - 多个包重复
MustRegister()同一指标会 panic:“duplicate metrics collector”,尤其在测试或模块化服务中容易踩坑 - 检查
curl http://localhost:8080/metrics | grep your_metric_name,确认 name 字段和代码中Name:完全一致(大小写、下划线都不能错)
如何正确打 HTTP 请求指标并避免高基数
直接把 r.URL.Path 或 r.Header.Get("X-User-ID") 当 label 值塞进 WithLabelValues(),等于给 Prometheus 喂“毒药”——每个用户、每个订单 ID 都生成一条新时间序列,内存爆、查询慢、存储崩。
- 路径中的动态段必须预处理:把
/api/v1/orders/12345映射为/api/v1/orders/{id},再传入 label - 状态码别直接用
r.StatusCode,先做映射:status := strconv.Itoa(r.StatusCode)或更稳妥地switch r.StatusCode { case 200: status = "200"; case 404: status = "404"; default: status = "other" } - 业务标签如
tenant_id要从 context 或 header 提取(比如r.Context().Value("tenant_id")),不能硬编码在 handler 里 - 标签名必须是合法标识符:全小写、下划线分隔,
tenant-id是非法的,得写成tenant_id
Counter 和 Histogram 怎么选、怎么配 buckets
Counter 只适合累计值(如总请求数、总错误数),不能反映速率或分布;Histogram 才是测耗时、响应体大小这类分布类指标的正解,但它不是“自动聪明”的——bucket 设置不合理,_bucket 就没意义。
- 别用
prometheus.DefBuckets硬套 HTTP 延迟:它的默认桶是[.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10]秒,对毫秒级 API 来说太粗,前几个桶永远为空 - 根据真实 P99 延迟设 bucket:比如你的 API P99 是 300ms,建议用
[]float64{0.05, 0.1, 0.2, 0.3, 0.5, 1.0}(单位是秒) - 打点时用
httpRequestDuration.WithLabelValues(r.Method, path).Observe(latency.Seconds()),别漏掉.Seconds() - 如果只关心平均延迟,用
Summary;如果要算 P99 或分位图,Histogram更合适且资源开销更低
本地能访问/metrics,但 Prometheus 抓不到
最常见的是监听地址绑定问题:Go 默认 http.ListenAndServe(":8080", nil) 绑定的是 localhost:8080(即 127.0.0.1:8080),而容器或远程 Prometheus 无法访问 localhost。
- 改成
http.ListenAndServe("0.0.0.0:8080", nil),让服务监听所有网卡 - 确认防火墙或 Docker 网络策略没拦截端口(尤其是 Kubernetes 中 Service 的 targetPort 和 Pod port 是否一致)
- Prometheus 配置里的
targets必须填服务可解析的地址,比如 K8s 中是my-service:8080,不是localhost:8080 - 用
netstat -tuln | grep 8080或ss -tuln | grep 8080看实际监听的是哪个 IP
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











