跳转到主内容
极星编程网:以代码为星,赴技术山海!

如何在Golang中利用Expvar监控运行时指标 Go语言标准库监控接口

expvar.NewInt和NewFloat未生效是因为创建后未注册到全局expvar.Var表;需显式调用expvar.Publish或使用expvar.Register传指针注册,否则curl /debug/vars看不到数据。 expvar.NewInt 和 expvar.NewFloat 为什么没效果? 因为
expvar
的变量必须注册到默认的
expvar.Publish
(即全局
expvar.Var
注册表)才可通过 HTTP 暴露,而
NewInt
/
NewFloat
返回的是未注册的裸变量。直接调用它们只是创建了对象,不自动挂载。 正确做法是:先用
expvar.NewInt("counter")
创建,再用
expvar.Publish("counter", counterVar)
显式注册(虽然更常用的是直接用
expvar.Get("counter")
获取已注册项,或改用
expvar.Do
遍历) 更省事的方式是跳过 NewXXX,直接用
expvar.Register("name", &intVar)
—— 注意传指针,且该变量需支持
expvar.Var
接口(
Int
和
Float
类型本身已实现) 常见错误现象:
curl http://localhost:6060/debug/vars
返回空 JSON 或找不到自定义字段,基本就是忘了注册或注册名拼错 如何让 expvar 在非标准端口暴露?
expvar
本身不启动 HTTP 服务,它只提供数据源;真正暴露靠你手动注册 handler 到某个
http.ServeMux
。默认
http.DefaultServeMux
上的
/debug/vars
路径,仅在你显式调用
http.ListenAndServe
且没传自定义 mux 时才“看起来”是自动的。 若要用 8081 端口:启动时写
http.ListenAndServe(":8081", nil)
,然后确保没其他 mux 覆盖
/debug/vars
若已有自定义 mux(比如用 gorilla/mux 或 http.ServeMux 实例),必须手动添加:
mux.HandleFunc("/debug/vars", expvar.Handler().ServeHTTP)
注意路径前缀:如果 mux 设置了
/api
前缀,别把
/debug/vars
错挂成
/api/debug/vars
——
expvar.Handler()
只响应精确匹配的
/debug/vars
自定义结构体指标导出后显示为 {} 怎么办?
expvar
对 struct 的序列化依赖其字段是否可导出(首字母大写)+ 是否实现了
expvar.Var
接口或
json.Marshaler
。裸 struct 默认被
json
包处理,但
expvar.Handler
内部用的是自己的编码逻辑,对未注册、无 Marshal 方法、字段不可导出的 struct 会输出空对象
{}
。 最简解法:让结构体字段全部大写,并嵌入
expvar.Map
或直接组合
expvar.Int
/
expvar.String
字段,例如:
type Stats struct { Total *expvar.Int; Errors *expvar.Int }
避免用
map[string]interface{}
存指标——类型擦除后
expvar
无法识别子值,容易变成
{"key":{}}
调试技巧:在 handler 中加一行
log.Printf("stats: %+v", stats)
,确认结构体字段值确实存在且非 nil expvar 和 pprof 能共用同一端口吗? 能,而且推荐这么做。两者都基于
http.DefaultServeMux
,只要不冲突路径即可共存:
/debug/vars
(expvar)、
/debug/pprof/
(pprof)互不干扰。 go语言参考手册 中文CHM版 Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译 下载 立即学习 “ go语言免费学习笔记(深入) ”; 标准做法是导入
_ "net/http/pprof"
,它会自动注册所有
/debug/pprof/*
路由到默认 mux;再确保
expvar
的 handler 也注册在同一 mux(即不传自定义 mux 给
http.ListenAndServe
) 常见坑:自己 new 了一个
http.ServeMux
并传给
ListenAndServe
,却忘了把 pprof 和 expvar handler 都加进去,结果只看到其中一个生效 性能影响极小:两者都是只读快照,无锁遍历,
expvar.Do
遍历所有注册变量的开销与变量数线性相关,百级别变量几乎无感 expvar 最容易被忽略的一点:它不采集任何指标,只提供注册和导出机制。计数器增减、延迟统计、内存快照……全得你自己在业务代码里调
myCounter.Add(1)
或
myGauge.Set(float64(time.Since(start).Microseconds()))
。没人替你埋点,也没自动采样周期。

相关文章