/metrics 返回空或404因未显式注册handler,需用http.Handle("/metrics", promhttp.Handler())或框架对应中间件,并确保注册早于http.ListenAndServe且路由未被覆盖。

用 prometheus/client_golang 暴露指标时,为什么 /metrics 返回空或 404?
默认情况下,prometheus/client_golang 不自动注册 HTTP handler,必须显式挂载。常见错误是只调用了 promhttp.Handler() 却没绑定到路由。
- 确保使用
http.Handle("/metrics", promhttp.Handler())(Go 1.22+ 推荐用http.HandleFunc+promhttp.Handler().ServeHTTP) - 若用
gin或echo等框架,需用对应中间件包装,例如gin.WrapH(promhttp.Handler()) - 检查是否在
http.ListenAndServe前执行了注册——顺序错会导致 handler 未生效 - 确认没有其他路由覆盖
/metrics,比如/*path兜底路由会拦截它
在 Kubernetes 中部署 Go 应用时,如何让 Prometheus 自动发现并抓取指标?
Prometheus 依赖 ServiceMonitor 或 PodMonitor(取决于 Operator 版本)来动态发现目标。单纯暴露 /metrics 端点并不足以被采集。
- Service 必须带
prometheus.io/scrape: "true"标签(适用于 vanilla Prometheus),或更推荐:用ServiceMonitorCRD 显式声明目标 - Service 的
ports[]需明确指定targetPort对应 Go 应用监听的端口(如8080),且该端口要与Pod容器端口一致 - 若指标端口不是主服务端口(比如另开
9091专用于 metrics),需在Service中单独定义该 port,并在ServiceMonitor的endpoints[].port中引用其名称 - 注意
namespace作用域:ServiceMonitor 默认只监控同 namespace,跨 namespace 需设置namespaceSelector
Counter 和 Gauge 选错会导致什么监控误判?
类型误用是 Go 监控中最隐蔽的问题之一,直接影响告警逻辑和趋势分析。
-
Counter只增不减,适合累计值(如请求总数、错误总数)。若用它记录当前并发请求数,重启后归零+重爬坡,图表会突降再飙升,被误判为故障 -
Gauge可增可减,适合瞬时值(如内存占用、活跃 goroutine 数)。若用它记录总请求数,当服务重启后旧值丢失,无法做跨周期求差(如 QPS 计算) - HTTP 请求耗时推荐用
Histogram或Summary,别用Gauge存平均值——它掩盖分布,且无法计算分位数 - 所有指标注册必须在程序启动早期完成,重复注册(如在 handler 里反复调
prometheus.NewCounter)会 panic
如何在 Go 应用中安全地注入 trace ID 并透传到 Prometheus 标签?
直接把 trace ID 当作 Prometheus 标签会导致高基数(cardinality explosion),引发存储暴涨和查询变慢。
立即学习“go语言免费学习笔记(深入)”;
- 绝对不要将
trace_id、request_id这类唯一值设为 label,Prometheus 不适合高基数维度 - 如需关联 traces 和 metrics,应在 OpenTelemetry Collector 层做关联,或通过日志(含 trace_id)与指标(含 service/endpoint 等低基数 label)在 Grafana 中联动查询
- 可用的低基数标签包括:
status_code(200/404/500)、method(GET/POST)、endpoint(/api/users,非 /api/users/123) - 若真需按 trace 分析,应走 tracing 系统(如 Jaeger/Tempo),而非硬塞进 Prometheus
curl -s localhost:9091/metrics | grep -v "^#" | wc -l 粗略评估指标行数——超过 5000 行就要警惕 label 组合爆炸。










