expvar 是 Go 标准库中轻量级运行时指标暴露机制,仅支持基础调试观测,不支持自定义标签、聚合或推送;启用需导入 _ "expvar" 并挂载至 /debug/vars;自定义指标须用 expvar.Int/Float 并通过 Add()/Set() 更新;注册须在 init/main 开头前且命名合法;与 pprof 可共存但需避免 DefaultServeMux 冲突;生产环境应替换为 Prometheus。

expvar 是 Go 标准库中轻量、开箱即用的运行时指标暴露机制,但它不支持自定义标签、聚合或推送模式——只适合内部调试和基础健康观测,别指望它替代 Prometheus。
如何启用 expvar HTTP 端点
Go 默认不暴露任何指标端点,必须显式注册 http.Handler。最简方式是挂载到 /debug/vars:
import "net/http"
import _ "expvar"
<p>func main() {
http.ListenAndServe(":6060", nil) // expvar 自动注册到 DefaultServeMux
}启动后访问 http://localhost:6060/debug/vars 即可看到 JSON 格式的内存、goroutine 数、GC 统计等。注意:expvar 仅响应 GET,且不支持 CORS 或认证。
如何注册自定义整数和浮点指标
expvar 提供 expvar.Int 和 expvar.Float 类型,它们是线程安全的,但只能通过 .Set() 更新,不能原子增减(这点常被误用):
- 错误写法:
myCounter.Value() + 1—— 返回的是拷贝值,修改无效 - 正确写法:
myCounter.Add(1)(Int支持),但Float没有Add,得用Set()手动计算 - 所有变量名必须是合法的 Go 标识符,否则注册失败且静默忽略
示例:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
var reqCount = expvar.NewInt("http_requests_total")
var uptimeSec = expvar.NewFloat("uptime_seconds")
<p>func init() {
uptimeSec.Set(float64(time.Since(startTime).Seconds()))
}</p><p>func handler(w http.ResponseWriter, r *http.Request) {
reqCount.Add(1)
// ...
}为什么你的自定义指标没出现在 /debug/vars 中
常见原因不是代码错,而是注册时机或命名冲突:
- 在
init()或main()开头前注册——expvar.Publish要求变量已初始化且全局可寻址 - 变量名与内置指标重名(如
"cmdline"、"memstats")——会被覆盖且无提示 - 使用了指针或结构体字段直接发布(如
expvar.Publish("x", &someStruct.Field))——不支持,只接受expvar.Var实现类型 - HTTP 复用
DefaultServeMux但其他包也调用了http.HandleFunc冲突——建议显式传入独立http.ServeMux
expvar 和 pprof 能共存吗?怎么避免端点冲突
可以共存,但默认都用 DefaultServeMux,且 net/http/pprof 会自动注册多个路径(如 /debug/pprof/)。只要不手动覆盖同一路由,二者互不干扰:
import _ "net/http/pprof" // 自动注册 /debug/pprof/* 路由 import _ "expvar" // 自动注册 /debug/vars
真正容易出问题的是你手动调用 http.Handle("/debug", ...) 或替换整个 DefaultServeMux。此时应改用独立 mux:
mux := http.NewServeMux()
mux.Handle("/debug/vars", expvar.Handler())
mux.Handle("/debug/pprof/", http.HandlerFunc(pprof.Index))
http.ListenAndServe(":6060", mux)注意:expvar.Handler() 返回的是一个函数,不是 http.Handler 实例,别漏掉括号。
expvar 的最大陷阱不是不会用,而是误以为它能长期承载生产监控——它的 JSON 输出无版本保证、无采样控制、无指标生命周期管理,一旦服务启停频繁或 goroutine 泄漏,/debug/vars 本身就会变慢甚至阻塞 HTTP 处理。真要上生产,该切 Prometheus client_golang 就别犹豫。

















