必须用promhttp.handler()暴露指标,因其内置openmetrics格式校验、标签转义、content-type协商、gzip压缩及并发安全遍历,手写响应极易因换行、编码、后缀或单位不合规导致抓取失败。

必须用 promhttp.Handler() 暴露指标,不能手写响应体——OpenMetrics 格式校验极严,错一个换行、少一个 # TYPE 行、标签值没转义,Prometheus 就报 text format parsing error 并丢弃整个抓取。
为什么 promhttp.Handler() 不可替代
OpenMetrics 要求每条指标前必须有 # TYPE 和 # HELP 行,标签键值需 URL 编码(如空格变 %20),末尾不能多空行,Content-Type 必须是 text/plain; charset=utf-8,还支持 Accept: application/openmetrics-text 自动协商。这些细节 promhttp.Handler() 全部内置处理;自己用 fmt.Fprint 拼字符串,99% 会挂。
- 它自动根据请求头决定返回 OpenMetrics 还是旧版 Prometheus 文本格式
- 内置 gzip 压缩(当客户端声明
Accept-Encoding: gzip) - 对注册器里所有指标做并发安全遍历,避免读写竞争导致 panic 或数据截断
- 遇到未注册指标或类型冲突时返回 500,并带清晰错误信息,而不是静默失败
/metrics 返回空或 500 的真实原因
不是端口不通,也不是路由没配,而是指标和 handler 没对上同一个 registry 实例。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 用了
prometheus.NewRegistry()却调promhttp.Handler()→ 默认 registry 为空,返回空页或 500 - 自定义 registry 里没显式注册
prometheus.NewGoCollector()→go_goroutines等运行时指标消失 - 在 HTTP handler 里动态调
prometheus.MustRegister()→ 多次注册同名指标,触发 panic - 指标名含大写字母或中划线(如
HttpRequestsTotal或http-requests-total)→ OpenMetrics 规范只允许小写字母、数字、下划线,注册直接失败
Counter 和 Gauge 的命名与后缀必须合规
OpenMetrics 不只是格式校验,还强制语义后缀。名字不对,PromQL 就无法识别聚合意图,rate()、histogram_quantile() 全失效。
-
Counter必须以_total结尾(如http_requests_total),否则rate()计算会出错甚至返回负数 -
Gauge不能加_total(如memory_usage_bytes),加了会被当成 Counter 解析,后续查询全乱 -
Histogram必须带_bucket、_sum、_count三组子指标,且le标签值要严格递增,漏一个或顺序错,histogram_quantile()直接返回 NaN - 自定义指标名禁止用
go_*或process_*前缀——它们被NewGoCollector和NewProcessCollector预占,重复注册会 panic
Label 值处理不当会直接拖垮 Prometheus
OpenMetrics 允许任意字符串作 label 值,但高基数 label(比如用户 ID、请求 trace_id、未规整的 URL 路径)会让单个指标爆炸成成千上万时间序列,吃光 Prometheus 内存。
- 路径类 label(如
/user/123)必须规整为/user/{id},不能直接塞原始值 - label 值里禁止出现空格、换行、双引号、反斜杠——它们必须被转义,
promhttp.Handler()会自动做,但你自己拼就容易漏 - 敏感字段(如手机号、token)绝不能打 label —— 不仅违反安全规范,还因基数高导致存储和查询性能断崖下跌
- 高频打点时别在循环里反复调
counterVec.WithLabelValues("a", "b"),应提前缓存实例,减少 map 查找开销
最常被忽略的一点:OpenMetrics 的 # UNIT 行虽非强制,但一旦写了就必须单位统一(如秒用 s,字节用 bytes),且不能和指标名里的单位冲突(http_request_duration_milliseconds 却写 # UNIT seconds 就是错的)。Prometheus 不报错,但 Grafana 展示和 PromQL 运算会出偏差。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










