Go微服务暴露运行时指标必须显式注册prometheus.NewGoCollector()并挂载promhttp.Handler()到/metrics路由,否则curl返回空或仅基础指标;自定义指标禁用go_、process_等保留前缀,且需避免在handler内重复注册导致panic。

Go微服务里没有JVM——这是Java的运行时环境,Go用的是自己的runtime包。如果你在配置中混用“JVM监控”和“Go微服务”,Prometheus抓不到指标,curl http://localhost:8080/metrics 返回空或只有基础指标,根本原因是目标暴露逻辑错配。
Go服务暴露运行时指标必须用 promhttp.Handler()
Go官方客户端库自带一组标准运行时指标(goroutine数、GC次数、内存分配等),但它们不会自动暴露,必须显式注册并挂载到HTTP路由上。
-
prometheus.MustRegister(prometheus.NewGoCollector())是默认启用的,无需手动调用;但如果你调用了prometheus.Unregister()或自定义了prometheus.NewRegistry(),这组指标就会丢失 - 暴露端点必须是
http.Handle("/metrics", promhttp.Handler()),不能写成http.HandleFunc("/metrics", ...)—— 后者会绕过客户端库的序列化逻辑,返回空响应或404 - 如果用gin等框架,别直接传
promhttp.Handler()给router.GET;要包装成适配器:func(c *gin.Context) { promhttp.Handler().ServeHTTP(c.Writer, c.Request) }
自定义指标命名和标签必须避开保留前缀
Prometheus对指标名有硬性约定:go_*、process_*、http_* 是客户端库保留前缀,你自己的指标绝不能以这些开头,否则会被覆盖或拒绝注册。
- 错误示例:
go_request_total、http_api_latency_seconds—— 这些名会被静默忽略或与内置指标冲突 - 推荐命名:
myapp_api_requests_total、myapp_order_processing_duration_seconds - 标签键名避免用
job、instance—— 这两个是Prometheus抓取时自动注入的,你在代码里硬编码会导致label冲突,查询时聚合异常
go-zero等框架的Prometheus集成默认不暴露运行时指标
像go-zero这类框架封装了HTTP中间件做请求计时和状态码统计(如 server_req_dur_seconds_bucket),但它默认不注册 prometheus.NewGoCollector(),也不会暴露 /metrics 端点——你得自己补上。
- 检查框架文档是否提供
EnableRuntimeMetrics类似开关;没有的话,必须在main入口手动加:prometheus.MustRegister(prometheus.NewGoCollector()) - go-zero的
Prometheus配置项(如Host/Port)只是告诉它“把请求指标打到哪”,不是开启指标暴露服务;/metrics端点仍需你独立启动一个HTTP server或复用已有路由 - 若用Docker部署,确保容器内端口映射正确,且
scrape_configs中 targets 指向容器内部IP(如host.docker.internal:8080),不是宿主机localhost
最常被跳过的一步:没验证 /metrics 响应体里是否真有 go_goroutines 或你定义的指标。别只看HTTP状态码200,要 grep 一下内容。另外,Counter 和 Gauge 的使用场景容易反着用——比如用 Counter 记录当前并发数,结果永远只增不减,查出来全是错的。

















