promhttp.Handler() 不够用,因为它仅暴露 HTTP 层指标(如请求数、耗时直方图),不采集 CPU、内存、磁盘等操作系统级指标;需结合 procfs 手动注册 Gauge 指标并使用自定义 Registry 注入 /metrics 路由。

直接暴露 /metrics 接口就能让 Prometheus 拉取指标,但仅靠默认指标(如 HTTP 请求总数、延迟直方图)无法反映云服务器真实运行状态——CPU 使用率、内存剩余、磁盘 I/O、网络吞吐这些操作系统级指标,Gin 本身不采集,必须手动对接系统采集器。
为什么 promhttp.Handler() 不够用
Gin 集成 promhttp.Handler() 只暴露了 HTTP 层面的指标:请求计数、响应码分布、耗时直方图。它不感知宿主机 CPU、内存、磁盘这些资源,更不会自动上报 node_cpu_seconds_total 或 node_memory_MemAvailable_bytes 这类节点指标。
常见错误现象:curl http://localhost:8080/metrics 返回一堆 http_* 指标,但 Grafana 里看不到服务器负载曲线——因为根本没采集。
- 想监控云服务器,必须引入
github.com/prometheus/client_golang/prometheus+ 系统采集器(如github.com/prometheus/procfs) - 不能只注册
promhttp.Handler(),还得手动注册自定义收集器(Collector)或复用node_exporter的采集逻辑 - 生产环境别用
prometheus.MustRegister()全局注册,应使用prometheus.NewRegistry()隔离指标,避免冲突
如何采集 CPU 和内存使用率(Go 原生方案)
不用部署独立 node_exporter,直接在 Gin 服务里嵌入轻量采集逻辑。核心是读取 /proc/stat 和 /proc/meminfo,转换为 Gauge 指标。
示例关键代码:
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/procfs"
)
<p>var (
cpuUsage = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "host_cpu_usage_percent",
Help: "CPU usage percentage (calculated from /proc/stat)",
})
memAvailable = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "host_memory_available_bytes",
Help: "Available memory in bytes (/proc/meminfo)",
})
)</p><p>func init() {
prometheus.MustRegister(cpuUsage, memAvailable)
}</p><p>func collectHostMetrics() {
fs, <em> := procfs.NewFS("/proc")
stats, </em> := fs.Stat()
// 计算 CPU 使用率(简化版,实际需两次采样差值)
total := stats.User + stats.Nice + stats.System + stats.Idle
idle := stats.Idle
cpuUsage.Set(float64(total-idle) / float64(total) * 100)</p><pre class="brush:php;toolbar:false;">mem, _ := fs.MemInfo()
memAvailable.Set(float64(mem.MemAvailable))}
- 每 15 秒调用一次
collectHostMetrics()(用time.Ticker),避免高频读/proc带来开销 -
procfs包版本要匹配 Go 版本(2026 年推荐 v0.12+),旧版在 ARM64 云服务器上可能解析/proc/stat失败 - 内存单位统一用字节(
bytes),和 Prometheus 社区约定一致,方便 Grafana 做单位换算
如何把指标注入 Gin 的 /metrics 路由
不能直接用 gin.WrapH(promhttp.Handler()),它只用默认 registry。必须显式传入自定义 registry,并确保 host 指标已注册。
正确写法:
reg := prometheus.NewRegistry()
reg.MustRegister(cpuUsage, memAvailable)
// 还可注册 HTTP 指标(用 gin-gonic/contrib/prometheus)
p := ginprometheus.NewPrometheus("api", nil)
p.RegisterOn(reg)
<p>r.GET("/metrics", gin.WrapH(promhttp.HandlerFor(reg, promhttp.HandlerOpts{})))
- 务必用
promhttp.HandlerFor(reg, ...),而不是promhttp.Handler(),否则自定义指标不会出现在响应里 -
gin-gonic/contrib/prometheus是社区维护的 Gin 专用 Prometheus 中间件,比手写 HTTP 指标更准(能区分路由模板如/api/v1/users/:id) - 如果用了 Zap 日志,可在采集函数里打 debug 日志,但别在
/metricshandler 里打,避免影响拉取性能
真正麻烦的不是写几行采集代码,而是指标口径一致性——比如 CPU 使用率,top 显示的是最近 1 分钟平均,而你代码里用单次 /proc/stat 差值算的是瞬时值。监控告警前,得先确认所有图表用的都是同一套计算逻辑。


















