直接暴露/metrics端点是Gin集成Prometheus最轻量可控方式;需用gin.WrapH(promhttp.Handler())挂载,避免绕过Gin中间件,且不可混用pprof。

如何让 Gin 服务暴露 Prometheus 可采集的 /metrics 端点
Gin 本身不提供指标暴露能力,必须手动集成 Prometheus 客户端。最直接的方式是用 prometheus/client_golang 注册一个 HTTP handler,并挂载到 Gin 路由上:
- 不要直接用
http.Handle("/metrics", promhttp.Handler()),这会绕过 Gin 的中间件链(比如日志、鉴权) - 正确做法是用
gin.WrapH(promhttp.Handler())将原生 handler 包装成 Gin 兼容的 handler - 建议只对
/metrics启用最小中间件,例如仅限 IP 白名单或 BasicAuth,避免监控端点拖慢指标采集 - 若使用
gin-contrib/prometheus,它会自动注册http_requests_total、http_request_duration_seconds等基础指标,但默认不包含业务自定义指标
otelgin 和 prometheus 两类监控能共存吗
可以,而且推荐共存:前者专注请求链路追踪(trace),后者专注聚合指标(metrics),二者数据维度互补,不存在冲突。
-
otelgin.Middleware()会在每个请求上下文中注入 trace ID,并记录耗时、状态码、路径等 span 属性,但不生成 Prometheus 风格的时序指标 - Prometheus 指标需显式调用
promauto.NewCounter()或promauto.NewHistogram()创建并.Inc()/.Observe() - 注意时间单位:Prometheus 的
http_request_duration_seconds是秒级浮点数,而otelgin默认记录的是毫秒整数 —— 若你用 OTLP exporter 接入 SigNoz 或 Jaeger,无需转换;但若想把 trace 耗时映射到 metrics,得自己做单位归一 - 两者共用同一组标签(如
service_name、endpoint)能提升在 Grafana 中关联分析的效率
为什么 gin-contrib/pprof 不该和生产环境的 Prometheus 指标混用
pprof 是诊断型工具,输出的是采样堆栈快照,不是时序指标;强行把它塞进 Prometheus 采集目标,会导致严重问题。
- Prometheus 拉取
/debug/pprof/profile会触发 CPU 采样,单次拉取可能持续 30 秒以上,极易引发服务卡顿甚至超时熔断 -
/debug/pprof/heap返回的是当前内存分配快照,体积大(常达几 MB),网络传输开销高,且无法被 Prometheus 正确解析为指标格式 - 真正该暴露给 Prometheus 的是封装好的
runtime.NumGoroutine()、runtime.ReadMemStats()等轻量指标,而非原始 pprof 接口 - 如果要用 pprof 分析性能,应单独启一个受限路由(如
/admin/pprof),并确保只允许内网或带认证访问
Gin 中自定义业务指标最容易漏掉的三件事
写 prometheus.CounterVec 或 HistogramVec 很容易,但上线后常因细节失效。
- 忘记调用
.WithLabelValues("xxx")就直接.Inc()—— 这会 panic,错误信息是collected metric was not a Counter,但实际是 label 绑定失败 - 在 goroutine 里异步更新指标时没加锁(比如订单回调成功后发消息,再异步更新
order_success_total),导致计数丢失或重复 - 用字符串拼接构造 label 值(如
userID + "_" + orderID),一旦值含非法字符(空格、/、{),整个指标会被 Prometheus 拒绝,且无明确报错提示
http_requests_total{path="/api/v1/order"} 和 order_create_total{status="success"} 必须能互相验证,否则可视化图表再漂亮也查不出问题。



















