go服务要让prometheus采集到业务指标,关键在于定义、注册、打点三步缺一不可:必须用prometheus.mustregister()显式注册自定义指标(如countervec),注册须在init()或main()开头完成,且/metrics端点需手动挂载到路由(如http.handle("/metrics", promhttp.handler()))。

Go服务要让Prometheus真正采集到有用的业务指标,关键不在“暴露/metrics”,而在于指标怎么定义、怎么注册、怎么打点——三步错一步,指标就失效或爆炸。
必须显式注册,否则/metrics里根本看不到
创建指标对象(比如prometheus.NewCounterVec)只是生成一个内存结构,不调prometheus.MustRegister(),它就不会出现在/metrics里。常见错误是只写定义、忘了注册,或者在多个包里重复注册同名指标,直接panic。
- 所有自定义指标变量应定义为包级变量,注册逻辑统一放在
init()或main()开头 - 若用自定义注册器(如
reg := prometheus.NewRegistry()),必须用promhttp.HandlerFor(reg, ...),不能用默认的promhttp.Handler() - 别在HTTP handler里动态新建指标再注册——这是高频panic来源
选对指标类型:Counter记累计,Gauge管瞬时状态
订单总数、请求次数这类只增不减的数据用Counter;当前活跃连接数、队列长度、内存使用量这类可增可减的瞬时值,必须用Gauge。拿Gauge当Counter用(比如每次请求Set(1)),会导致语义混乱、聚合失真。
-
Counter只支持Inc()和Add(),不支持减操作;并发安全,无需额外锁 -
Gauge支持Set()、Add()、Inc()、Dec(),但goroutine退出时记得Dec(),否则活跃数永远不准 - 直方图(
Histogram)适合延迟分布统计,别用Gauge硬凑P99
带标签的指标要预定义、防爆炸、控维度
业务监控要有意义,就得带真实业务标签,比如tenant_id、service、workflow_stage,而不是只靠method和status。但标签设计不当,会引发指标基数爆炸,拖垮Prometheus存储和查询性能。
- 标签名必须全小写、下划线分隔(如
tenant_id,不能写tenant-id或TenantID) - 路径中动态ID(如
/order/12345)必须归一化为占位符(如/order/{id})再打点 - 避免高基数标签:用户ID、手机号、traceID等字段别直接塞进label,改用
counter按error_type分类或采样上报 - 用
CounterVec/GaugeVec定义指标,WithLabelValues()传值顺序必须和定义时[]string{"a","b","c"}完全一致
HTTP服务暴露/metrics端点必须手动挂载
Go默认的http.DefaultServeMux不会自动绑定/metrics,只调MustRegister()没用。Prometheus抓取返回404或空响应,90%是因为这一步漏了。
- 标准写法:
http.Handle("/metrics", promhttp.Handler()),且必须在http.ListenAndServe()之前执行 - 用Gin框架:用
router.GET("/metrics", gin.WrapH(promhttp.Handler())) - 用Echo框架:用
e.GET("/metrics", echo.WrapHandler(promhttp.Handler())) - 路径名不必非得是
/metrics,但必须和Prometheus配置中scrape_configs.metrics_path严格一致
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











