必须显式注册promhttp.Handler()并确保在http.ListenAndServe()之前完成,否则Prometheus抓取返回404或空响应;自定义指标需包级定义、仅启动时注册一次,计数器不可用于活跃连接统计而应改用Gauge。

Go微服务暴露的指标默认不被Prometheus直接抓取,必须手动集成promhttp并注册http.Handler,否则scrape会返回404或空响应。
如何让Go服务暴露/metrics端点
Go标准库不自带指标暴露能力,需引入prometheus/client_golang,并在HTTP路由中显式挂载promhttp.Handler()。常见错误是只调用prometheus.MustRegister()但没挂载Handler,导致Prometheus反复报server returned HTTP status 404 Not Found。
- 确保在
http.ListenAndServe前注册Handler,例如:http.Handle("/metrics", promhttp.Handler()) - 路径必须严格匹配Prometheus配置中的
metrics_path(默认/metrics),大小写和尾部斜杠都要一致 - 避免用
gorilla/mux等路由库时忘记调用router.Use或漏掉router.Handle,建议初期先用net/http原生方式验证
哪些指标值得在Go服务里主动暴露
基础运行时指标(如go_goroutines、go_memstats_alloc_bytes)由prometheus.DefaultGatherer自动收集,但业务关键路径需要手动定义。盲目暴露所有变量会导致cardinality爆炸,拉垮Prometheus性能。
- 优先暴露有明确SLO意义的指标:如
http_request_duration_seconds_bucket(带method、status标签)、grpc_server_handled_total - 避免用请求ID、用户ID这类高基数字段做标签,改用预定义分类(如
user_tier="premium") - 计数器(
prometheus.NewCounterVec)比仪表盘(Gauge)更安全——不会因重启归零问题引发误告警
Prometheus配置里怎么写job才能正确抓取
Go服务若部署在Kubernetes中,常因Service DNS解析失败或Pod未就绪导致target状态为down;若跑在物理机或Docker Compose里,则容易忽略static_configs的IP可达性。
- 用
targets: ["host.docker.internal:8080"]代替127.0.0.1(Docker for Mac/Windows下localhost不指向宿主机) - K8s场景优先用
serviceMonitor而非静态配置,避免硬编码Endpoint IP - 务必设置
scrape_timeout大于服务响应耗时,尤其当/metrics包含慢查询或未缓存的聚合计算时
最常被跳过的一步:在Go服务启动日志里加一行log.Printf("metrics endpoint registered at :8080/metrics"),而不是依赖文档或记忆——因为端口冲突、防火墙拦截、反向代理rewrite规则都会让/metrics静默失效。











