Go语言实现简单监控程序_Go系统信息采集项目
技术百科
P粉602998670
发布时间:2026-01-27
浏览: 次 优先选 gopsutil 而非原生 syscall 或 /proc:它跨平台抽象了 Linux/cgroup v2、Windows/macOS 差异,但需注意 cpu.Percent() 必须传 time.Duration 才采样、disk.Usage() 在容器中需先用 disk.Partitions(true) 查真实挂载点、host.Info() 在 Alpine 中 fallback 到空字符串。
Go 语言写系统监控程序,核心不是“能不能”,而是“要不要自己造轮子”——gopsutil 已覆盖绝大多数场景,直接用它比手撸 /proc 解析或调用 sysctl 稳定得多。
为什么优先选 gopsutil 而不是原生 syscall 或 /proc
自己读 /proc/meminfo 或调用 runtime.ReadMemStats() 看内存,看似轻量,但很快会遇到:不同 Linux 发行版 /proc 字段顺序不一致、cgroup v2 下 /proc/cgroups 不再可用、Windows/macOS 完全不可用。而 gopsutil 在这些平台做了抽象和 fallback。
-
gopsutil的cpu.Percent()默认返回每核使用率,加time.Second参数才触发采样;漏传会导致返回全 0 -
disk.Usage("/path")在容器中可能因挂载命名空间隔离失败,需配合disk.Partitions(true)先查真实挂载点 - 它的
host.Info()依赖/etc/os-release,Alpine 镜像里默认没这个文件,会 fallback 到空字符串
采集 CPU/内存/磁盘时必须设对的参数
默认行为往往不是你想要的。比如 cpu.Percent() 不传 time.Duration 就不会真正采样,mem.VirtualMemory() 返回的是瞬时快照,不带历史趋势。
package main
import (
"fmt"
"time"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/mem"
"github.com/shirou/gopsutil/disk"
)
func main() {
// ✅ 正确:指定采样间隔,否则返回 []float64{}
percents, _ := cpu.Percent(time.Second, false)
fmt.Printf("CPU: %.1f%%\n", percents[0])
// ✅ 正确:获取当前内存使用
v, _ := mem.VirtualMemory()
fmt.Printf("Me
m: %.1f%% used (%d/%d MB)\n", v.UsedPercent, v.Used/1024/1024, v.Total/1024/1024)
// ✅ 正确:先找根分区,避免硬编码 "/"
parts, _ := disk.Partitions(true)
for _, p := range parts {
if p.Mountpoint == "/" {
du, _ := disk.Usage(p.Mountpoint)
fmt.Printf("Disk /: %.1f%% used\n", du.UsedPercent)
break
}
}
}
HTTP 暴露指标时别直接用 net/http 返回 JSON
裸写 http.HandleFunc + json.Marshal 看似简单,但会快速撞上三个问题:并发采集冲突(多个请求同时调 cpu.Percent())、无超时控制(disk.Usage() 在 NFS 挂死时卡住整个 handler)、指标格式不兼容 Prometheus。
- 用
sync.Once或sync.RWMutex保护采集逻辑,避免重复初始化或并发读写结构体 - 所有
gopsutil调用必须包在context.WithTimeout里,例如ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - 如果后续要对接 Prometheus,直接用
prometheus.NewGaugeVec+promhttp.Handler(),别自己拼/metrics文本
容器环境下的常见失效点
在 Docker/K8s 里跑 Go 监控程序,gopsutil 默认行为会误判宿主机资源。关键不是“能不能运行”,而是“它读的是哪一层的视图”。
- 容器内执行
host.Info()返回的是宿主机的hostname和uptime,但os.Getpid()是容器 PID,混用会导致日志混乱 -
process.Pids()默认列出所有进程,包括宿主机的,需过滤p.Pid > 0 && p.Pid (容器 PID 通常较小)或读/proc/1/cgroup判断是否在容器中 - 想查容器自身 CPU limit,得解析
/sys/fs/cgroup/cpu/cpu.cfs_quota_us,gopsutil不提供该接口,必须手动读
真正难的不是采集数据,而是明确“这个值在当前运行环境中代表什么”。比如 cpu.Times(false) 返回的 user 时间,在容器里是受限于 cgroup 的,还是宿主机全局的——得看你是从 /proc/stat 还是 /sys/fs/cgroup/cpu/xxx/cpu.stat 读的。
# ai
# windows
# go语言
# mac
# linux
# js
# json
# go
# docker
# golang
# 编码
# 字符串
# 接口
# git
# github
# 结构体
# 命名空间
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- 如何在Golang中定义接口_抽象方法和多态实现
- Windows家庭版如何开启组策略(gpedit.
- 如何关闭Win10自动更新更新_Win10系统自动
- 如何在Golang中实现邮件发送功能_Golang
- Python函数缓存机制_lru_cache解析【
- Windows10如何查看蓝屏日志_Win10使用
- Linux如何安装JDK11_Linux环境变量配
- 本地php环境打开php文件直接下载_浏览器解析p
- Windows10如何删除恢复分区_Win10 D
- php怎么下载安装后无法解析php文件_服务器配置
- Win11截图快捷键是什么_Win11自带截图工具
- php高频调试功能有哪些_php常用调试函数与工具
- 如何使用Golang包导出规则_控制函数和变量可见
- 如何使用Golang优化模块引入路径_Golang
- Windows10如何彻底关闭自动更新_Win10
- c++ reinterpret_cast怎么用 c
- MAC如何隐藏文件夹及文件_MAC终端命令隐藏与第
- Linux如何使用Curl发送请求_Linux下A
- 如何使用Golang捕获并记录协程panic_保证
- Win11怎么设置任务栏图标大小_Windows1
- 如何更改Windows资源管理器的默认启动位置?(
- Win10怎么卸载鲁大师_Win10彻底卸载鲁大师
- Win11怎么关闭搜索历史_Win11清除任务栏搜
- Go语言中slice追加操作的底层共享机制详解
- c++ std::atomic如何保证原子性 c+
- Python迭代器生成器进阶教程_节省内存与懒加载
- c++怎么操作redis数据库_c++ hired
- php会话怎么开启_session_start函数
- mac本地php环境如何开启curl_curl扩展
- Win11怎么关闭通知消息_屏蔽Windows 1
- c# 如何用c#实现一个支持优先级的任务队列
- 如何在 Go 中调用动态链接库(.so)中的函数
- 如何在网页无标准表格标签时高效提取结构化数据
- Win11怎么关闭搜索历史 Win11清除搜索框最
- 如何使用Golang reflect检查方法数量_
- Win11 explorer.exe频繁崩溃_修复
- Win11如何开启telnet服务 Win11启用
- c# 在ASP.NET Core中管理和取消后台任
- 如何使用正则表达式提取以编号开头、后跟多个注解的完
- PythonGIL机制理解_多线程限制解析【教程】
- 如何在 Go 同包不同文件中正确引用结构体
- Win11怎么关闭小组件_Win11禁用任务栏天气
- Windows10无法识别USB设备描述符请求失败
- 如何在 Django 中安全修改用户密码而不使会话
- Win11怎样安装企业微信_Win11安装企业微信
- Win11怎么开启HDR模式_Windows 11
- How to Properly Use NumPy
- Windows驱动无法加载错误解决方法_驱动签名验
- Win11怎么激活Windows10_Win11激
- 如何优化Golang程序CPU性能_Golang


QQ客服