/metrics端点需手动注册、触发、暴露指标,缺一不可;Go运行时指标如go_goroutines默认不注册,自定义指标未调用Inc()则不输出,Vec与裸指标不可混用,label须合法且维度设计合理。

直接暴露 /metrics 端点不会自动给你 Go 运行时指标,也不会让自定义指标“自己长出来”——必须手动注册、手动触发、独立暴露,三步缺一不可。
为什么 /metrics 里看不到 go_goroutines 或你定义的 Counter
根本原因是指标没注册或没触发。Prometheus 不会扫描你的变量,它只读取注册表里已注册且被调用过的指标。
-
go_goroutines这类运行时指标默认不注册,得显式加一行:prometheus.MustRegister(prometheus.NewGoCollector()) - 自定义的
httpRequestsTotal是CounterVec,但如果你只声明没调.WithLabelValues("GET", "/api").Inc(),它压根不会出现在/metrics输出里——Counter 不上报零值,这是设计使然,不是 bug - label 值传空字符串或
nil会 panic;声明了两个 label(如[]string{"method", "endpoint"}),调用时却只传一个,或顺序颠倒,指标就静默丢失,/metrics里查不到也无报错
为什么 Prometheus 抓不到指标:先查网络和配置,别碰 Go 代码
90% 的“抓不到”问题跟 Go 实现无关,卡在三处:
-
scrape_configs.targets写的是localhost:8080?宿主机上的 Prometheus 访问不了容器内网,得换成host.docker.internal:8080(Docker Desktop)或真实局域网 IP - Go 服务监听绑定了
127.0.0.1:8080?改成:8080(即监听所有接口),否则外部请求连不上 - 防火墙或云服务器安全组没放行监控端口(比如
:9091)?在 Prometheus 所在机器上跑curl -v http://your-go-app:9091/metrics,不通就别查 Go 逻辑了
别把 /metrics 挂在业务 HTTP mux 上
混用业务路由和监控端点,等于把监控和被监控绑在同一根绳上,风险极高。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
立即学习“go语言免费学习笔记(深入)”;
- 业务中间件可能改写响应头,比如加了
Content-Type: text/html,而 Prometheus 要求text/plain; charset=utf-8,结果报错:expected 'text/plain' response, got 'text/html' - 业务 handler panic 会导致整个
http.Server崩溃,/metrics一起挂掉——你连告警都收不到 - 正确做法是起一个独立
http.Server,只挂promhttp.Handler():go http.Handle("/metrics", promhttp.Handler()) http.ListenAndServe(":9091", nil)
Vec 和裸指标别混用,label 维度设计决定能不能查到数据
用 NewCounter 却调 .WithLabelValues()?直接 panic。用 NewCounterVec 却漏注册?/metrics 里彻底消失。
- 所有指标必须在
init()或main()开头注册,不能在 handler 里反复New+MustRegister,否则报duplicate metrics collector registration attempted - label 名必须是合法标识符(小写字母/数字/下划线),
pay-channel会 panic,pay_channel才行 - ConstLabels 只适合固定值(如
version,instance),别往里塞请求级动态值(如user_id),否则 label 组合爆炸,内存和查询性能双双崩盘
最容易被忽略的其实是注册时机和 label 校验——指标对象创建了不等于能被采集,调用了 .Inc() 不等于数据能被正确分组,差一个字符、少一次注册、多一层中间件,监控就断在看不见的地方。

















