内容简介:先安装:由于
简介
gopsutil 是 Python 工具库 psutil 的 Golang 移植版,可以帮助我们方便地获取各种系统和硬件信息。 gopsutil 为我们屏蔽了各个系统之间的差异,具有非常强悍的可移植性。有了 gopsutil ,我们不再需要针对不同的系统使用 syscall 调用对应的系统方法。更棒的是 gopsutil 的实现中没有任何 cgo 的代码,使得交叉编译成为可能。
快速使用
先安装:
$ go get github.com/shirou/gopsutil
由于 gopsutil 库用到了 golang.org/x/sys ,后者在墙外,如果有类似下面的报错:
cannot find package "golang.org/x/sys/windows"
可使用下面的命令下载 golang.org/x/sys 在 GitHub 上的镜像:
$ git clone git@github.com:golang/sys.git $GOPATH/src/golang.org/x/sys
使用:
package main
import (
"fmt"
"github.com/shirou/gopsutil/mem"
)
func main() {
v, _ := mem.VirtualMemory()
fmt.Printf("Total: %v, Available: %v, UsedPercent:%f%%\n", v.Total, v.Available, v.UsedPercent)
fmt.Println(v)
}
gopsutil 将不同的功能划分到不同的子包中:
cpu disk docker host mem net process winservices
想要使用对应的功能,要导入对应的子包。例如,上面代码中,我们要获取内存信息,导入的是 mem 子包。 mem.VirtualMemory() 方法返回内存信息结构 mem.VirtualMemoryStat ,该结构有丰富的字段,我们最常使用的无外乎 Total (总内存)、 Available (可用内存)、 Used (已使用内存)和 UsedPercent (内存使用百分比)。 mem.VirtualMemoryStat 还实现了 fmt.Stringer 接口,以 JSON 格式返回内存信息。语句 fmt.Println(v) 会自动调用 v.String() ,将返回信息输出。程序输出:
Total: 8526921728, Available: 3768975360, UsedPercent:55.000000%
{"total":8526921728,"available":3768975360,"used":4757946368,"usedPercent":55,"free":0,"active":0,"inactive":0,"wired":0,"laundry":0,"buffers":0,"cached":0,"writeback":0,"dirty":0,"writebacktmp":0,"shared":0,"slab":0,"sreclaimable":0,"sunreclaim":0,"pagetables":0,"swapcached":0,"commitlimit":0,"committedas":0,"hightotal":0,"highfree":0,"lowtotal":0,"lowfree":0,"swaptotal":0,"swapfree":0,"mapped":0,"vmalloctotal":0,"vmallocused":0,"vmallocchunk":0,"hugepagestotal":0,"hugepagesfree":0,"hugepagesize":0}
单位为字节,我的电脑内存 8GB,当前使用百分比为 55%,可用内存 3768975360B(即 3.51GB)。
CPU
我们知道 CPU 的核数有两种,一种是物理核数,一种是逻辑核数。物理核数就是主板上实际有多少个 CPU,一个物理 CPU 上可以有多个核心,这些核心被称为逻辑核。 gopsutil 中 CPU 相关功能在 cpu 子包中, cpu 子包提供了获取物理和逻辑核数、CPU 使用率的接口:
-
Counts(logical bool):传入false,返回物理核数,传入true,返回逻辑核数; -
Percent(interval time.Duration, percpu bool):表示获取interval时间间隔内的 CPU 使用率,percpu为false时,获取总的 CPU 使用率,percpu为true时,分别获取每个 CPU 的使用率,返回一个[]float64类型的值。
例如:
func main() {
physicalCnt, _ := cpu.Counts(false)
logicalCnt, _ := cpu.Counts(true)
fmt.Printf("physical count:%d logical count:%d\n", physicalCnt, logicalCnt)
totalPercent, _ := cpu.Percent(3*time.Second, false)
perPercents, _ := cpu.Percent(3*time.Second, true)
fmt.Printf("total percent:%v per percents:%v", totalPercent, perPercents)
}
上面代码获取物理核数和逻辑核数,并获取 3s 内的总 CPU 使用率和每个 CPU 各自的使用率,程序输出(注意每次运行输出可能都不相同):
physical count:4 logical count:8 total percent:[30.729166666666668] per percents:[32.64248704663213 26.94300518134715 44.559585492227974 23.958333333333336 36.787564766839374 20.3125 38.54166666666667 28.125]
详细信息
调用 cpu.Info() 可获取 CPU 的详细信息,返回 []cpu.InfoStat :
func main() {
infos, _ := cpu.Info()
for _, info := range infos {
data, _ := json.MarshalIndent(info, "", " ")
fmt.Print(string(data))
}
}
为了方便查看,我使用 JSON 输出结果:
{
"cpu": 0,
"vendorId": "GenuineIntel",
"family": "198",
"model": "",
"stepping": 0,
"physicalId": "BFEBFBFF000906E9",
"coreId": "",
"cores": 8,
"modelName": "Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz",
"mhz": 3601,
"cacheSize": 0,
"flags": [],
"microcode": ""
}
由结果可以看出,CPU 是 Intel 的 i7-7700 系列,频率 3.60GHz。上面是我在 Windows 上运行的返回结果,内部使用了 github.com/StackExchange/wmi 库。在 Linux 下每个逻辑 CPU 都会返回一个 InfoStat 结构。
时间占用
调用 cpu.Times(percpu bool) 可以获取从开机算起,总 CPU 和 每个单独的 CPU 时间占用情况。传入 percpu=false 返回总的,传入 percpu=true 返回单个的。每个 CPU 时间占用情况是一个 TimeStat 结构:
// src/github.com/shirou/gopsutil/cpu/cpu.go
type TimesStat struct {
CPU string `json:"cpu"`
User float64 `json:"user"`
System float64 `json:"system"`
Idle float64 `json:"idle"`
Nice float64 `json:"nice"`
Iowait float64 `json:"iowait"`
Irq float64 `json:"irq"`
Softirq float64 `json:"softirq"`
Steal float64 `json:"steal"`
Guest float64 `json:"guest"`
GuestNice float64 `json:"guestNice"`
}
-
CPU:CPU 标识,如果是总的,该字段为cpu-total,否则为cpu0、cpu1...; -
User:用户时间占用(用户态); -
System:系统时间占用(内核态); -
Idle:空闲时间; - ...
例如:
func main() {
infos, _ := cpu.Times(true)
for _, info := range infos {
data, _ := json.MarshalIndent(info, "", " ")
fmt.Print(string(data))
}
}
为了方便查看,我用 JSON 输出结果,下面是其中一个输出:
{
"cpu": "cpu0",
"user": 674.46875,
"system": 1184.984375,
"idle": 7497.1875,
"nice": 0,
"iowait": 0,
"irq": 75.578125,
"softirq": 0,
"steal": 0,
"guest": 0,
"guestNice": 0
}
磁盘
子包 disk 用于获取磁盘信息。 disk 可获取 IO 统计、分区和使用率信息。下面依次介绍。
IO 统计
调用 disk.IOCounters() 函数,返回的 IO 统计信息用 map[string]IOCountersStat 类型表示。每个分区一个结构,键为分区名,值为统计信息。这里摘取统计结构的部分字段,主要有读写的次数、字节数和时间:
// src/github.com/shirou/gopsutil/disk/disk.go
type IOCountersStat struct {
ReadCount uint64 `json:"readCount"`
MergedReadCount uint64 `json:"mergedReadCount"`
WriteCount uint64 `json:"writeCount"`
MergedWriteCount uint64 `json:"mergedWriteCount"`
ReadBytes uint64 `json:"readBytes"`
WriteBytes uint64 `json:"writeBytes"`
ReadTime uint64 `json:"readTime"`
WriteTime uint64 `json:"writeTime"`
// ...
}
例如:
func main() {
mapStat, _ := disk.IOCounters()
for name, stat := range mapStat {
fmt.Println(name)
data, _ := json.MarshalIndent(stat, "", " ")
fmt.Println(string(data))
}
}
输出包括所有分区,我这里只展示一个:
C:
{
"readCount": 184372,
"mergedReadCount": 0,
"writeCount": 42252,
"mergedWriteCount": 0,
"readBytes": 5205152768,
"writeBytes": 701583872,
"readTime": 333,
"writeTime": 27,
"iopsInProgress": 0,
"ioTime": 0,
"weightedIO": 0,
"name": "C:",
"serialNumber": "",
"label": ""
}
注意, disk.IOCounters() 可传入可变数量的字符串参数用于标识分区, 此参数在 Windows 上无效 。
分区
调用 disk.PartitionStat(all bool) 函数,返回分区信息。如果 all = false ,只返回实际的物理分区(包括硬盘、CD-ROM、USB),忽略其它的虚拟分区。如果 all = true 则返回所有的分区。返回类型为 []PartitionStat ,每个分区对应一个 PartitionStat 结构:
// src/github.com/shirou/gopsutil/disk/
type PartitionStat struct {
Device string `json:"device"`
Mountpoint string `json:"mountpoint"`
Fstype string `json:"fstype"`
Opts string `json:"opts"`
}
-
Device:分区标识,在 Windows 上即为C:这类格式; -
Mountpoint:挂载点,即该分区的文件路径起始位置; -
Fstype:文件系统类型,Windows 常用的有 FAT、NTFS 等,Linux 有 ext、ext2、ext3等; -
Opts:选项,与系统相关。
例如:
func main() {
infos, _ := disk.Partitions(false)
for _, info := range infos {
data, _ := json.MarshalIndent(info, "", " ")
fmt.Println(string(data))
}
}
我的 Windows 机器输出(只展示第一个分区):
{
"device": "C:",
"mountpoint": "C:",
"fstype": "NTFS",
"opts": "rw.compress"
}
由上面的输出可知,我的第一个分区为 C: ,文件系统类型为 NTFS 。
使用率
调用 disk.Usage(path string) 即可获得路径 path 所在磁盘的使用情况,返回一个 UsageStat 结构:
// src/github.com/shirou/gopsutil/disk.go
type UsageStat struct {
Path string `json:"path"`
Fstype string `json:"fstype"`
Total uint64 `json:"total"`
Free uint64 `json:"free"`
Used uint64 `json:"used"`
UsedPercent float64 `json:"usedPercent"`
InodesTotal uint64 `json:"inodesTotal"`
InodesUsed uint64 `json:"inodesUsed"`
InodesFree uint64 `json:"inodesFree"`
InodesUsedPercent float64 `json:"inodesUsedPercent"`
}
Path Fstype Total Free Used UsedPercent
例如:
func main() {
info, _ := disk.Usage("D:/code/golang")
data, _ := json.MarshalIndent(info, "", " ")
fmt.Println(string(data))
}
由于返回的是磁盘的使用情况,所以路径 D:/code/golang 和 D: 返回同样的结果,只是结构中的 Path 字段不同而已。程序输出:
{
"path": "D:/code/golang",
"fstype": "",
"total": 475779821568,
"free": 385225650176,
"used": 90554171392,
"usedPercent": 19.032789388496106,
"inodesTotal": 0,
"inodesUsed": 0,
"inodesFree": 0,
"inodesUsedPercent": 0
}
主机
子包 host 可以获取主机相关信息,如开机时间、内核版本号、平台信息等等。
开机时间
host.BootTime() 返回主机开机时间的时间戳:
func main() {
timestamp, _ := host.BootTime()
t := time.Unix(int64(timestamp), 0)
fmt.Println(t.Local().Format("2006-01-02 15:04:05"))
}
上面先获取开机时间,然后通过 time.Unix() 将其转为 time.Time 类型,最后输出 2006-01-02 15:04:05 格式的时间:
2020-04-06 20:25:32
内核版本和平台信息
func main() {
version, _ := host.KernelVersion()
fmt.Println(version)
platform, family, version, _ := host.PlatformInformation()
fmt.Println("platform:", platform)
fmt.Println("family:", family,
fmt.Println("version:", version)
}
在我的 Win10 上运行输出:
10.0.18362 Build 18362 platform: Microsoft Windows 10 Pro family: Standalone Workstation version: 10.0.18362 Build 18362
终端用户
host.Users() 返回终端连接上来的用户信息,每个用户一个 UserStat 结构:
// src/github.com/shirou/gopsutil/host/host.go
type UserStat struct {
User string `json:"user"`
Terminal string `json:"terminal"`
Host string `json:"host"`
Started int `json:"started"`
}
字段一目了然,看示例:
func main() {
users, _ := host.Users()
for _, user := range users {
data, _ := json.MarshalIndent(user, "", " ")
fmt.Println(string(data))
}
}
内存
在中,我们演示了如何使用 mem.VirtualMemory() 来获取内存信息。该函数返回的只是物理内存信息。我们还可以使用 mem.SwapMemory() 获取交换内存的信息,信息存储在结构 SwapMemoryStat 中:
// src/github.com/shirou/gopsutil/mem/
type SwapMemoryStat struct {
Total uint64 `json:"total"`
Used uint64 `json:"used"`
Free uint64 `json:"free"`
UsedPercent float64 `json:"usedPercent"`
Sin uint64 `json:"sin"`
Sout uint64 `json:"sout"`
PgIn uint64 `json:"pgin"`
PgOut uint64 `json:"pgout"`
PgFault uint64 `json:"pgfault"`
}
字段含义很容易理解, PgIn/PgOut/PgFault 这三个字段我们重点介绍一下。交换内存是以 页 为单位的,如果出现缺页错误( page fault ),操作系统会将磁盘中的某些页载入内存,同时会根据特定的机制淘汰一些内存中的页。 PgIn 表征载入页数, PgOut 淘汰页数, PgFault 缺页错误数。
例如:
func main() {
swapMemory, _ := mem.SwapMemory()
data, _ := json.MarshalIndent(swapMemory, "", " ")
fmt.Println(string(data))
}
进程
process 可用于获取系统当前运行的进程信息,创建新进程,对进程进行一些操作等。
func main() {
var rootProcess *process.Process
processes, _ := process.Processes()
for _, p := range processes {
if p.Pid == 0 {
rootProcess = p
break
}
}
fmt.Println(rootProcess)
fmt.Println("children:")
children, _ := rootProcess.Children()
for _, p := range children {
fmt.Println(p)
}
}
先调用 process.Processes() 获取当前系统中运行的所有进程,然后找到 Pid 为 0 的进程,即操作系统的第一个进程,最后调用 Children() 返回其子进程。还有很多方法可获取进程信息,感兴趣可查看文档了解~
Windows 服务
winservices 子包可以获取 Windows 系统中的服务信息,内部使用了 golang.org/x/sys 包。在 winservices 中,一个服务对应一个 Service 结构:
// src/github.com/shirou/gopsutil/winservices/winservices.go
type Service struct {
Name string
Config mgr.Config
Status ServiceStatus
// contains filtered or unexported fields
}
mgr.Config 为包 golang.org/x/sys 中的结构,该结构详细记录了服务类型、启动类型(自动/手动)、二进制文件路径等信息:
// src/golang.org/x/sys/windows/svc/mgr/config.go
type Config struct {
ServiceType uint32
StartType uint32
ErrorControl uint32
BinaryPathName string
LoadOrderGroup string
TagId uint32
Dependencies []string
ServiceStartName string
DisplayName string
Password string
Description string
SidType uint32
DelayedAutoStart bool
}
ServiceStatus 结构记录了服务的状态:
// src/github.com/shirou/gopsutil/winservices/winservices.go
type ServiceStatus struct {
State svc.State
Accepts svc.Accepted
Pid uint32
Win32ExitCode uint32
}
State Accepts Pid Win32ExitCode
下面程序中,我将系统中所有服务的名称、二进制文件路径和状态输出到控制台:
func main() {
services, _ := winservices.ListServices()
for _, service := range services {
newservice, _ := winservices.NewService(service.Name)
newservice.GetServiceDetail()
fmt.Println("Name:", newservice.Name, "Binary Path:", newservice.Config.BinaryPathName, "State: ", newservice.Status.State)
}
}
注意,调用 winservices.ListServices() 返回的 Service 对象信息是不全的,我们通过 NewService() 以该服务名称创建一个服务,然后调用 GetServiceDetail() 方法获取该服务的详细信息。不能直接通过 service.GetServiceDetail() 来调用,因为 ListService() 返回的对象缺少必要的系统资源句柄(为了节约资源),调用 GetServiceDetail() 方法会 panic !!!
错误和超时
由于大部分函数都涉及到底层的系统调用,所以发生错误和超时是在所难免的。几乎所有的接口都有两个返回值,第二个作为错误。在前面的例子中,我们为了简化代码都忽略了错误,在实际使用中,建议对错误进行处理。
另外,大部分接口都是一对,一个不带 context.Context 类型的参数,另一个带有该类型参数,用于做上下文控制。在内部调用发生错误或超时后能及时处理,避免长时间等待返回。实际上,不带 context.Context 参数的函数内部都是以 context.Background() 为参数调用带有 context.Context 的函数的:
// src/github.com/shirou/gopsutil/cpu_windows.go
func Times(percpu bool) ([]TimesStat, error) {
return TimesWithContext(context.Background(), percpu)
}
func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
// ...
}
总结
gopsutil 库方便了我们获取本机的信息,且很好地处理了各个系统间的兼容问题,提供了一致的接口。还有几个子包例如 net/docker 限于篇幅没有介绍,感兴趣的童鞋可自行探索。
大家如果发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue:smile:
参考
- gopsutil GitHub: https://github.com/shirou/gopsutil
- Go 每日一库 GitHub: https://github.com/darjun/go-daily-lib
我
我的博客: https://darjun.github.io
欢迎关注我的微信公众号【GoUpUp】,共同学习,一起进步~
以上所述就是小编给大家介绍的《Go 每日一库之 gopsutil》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
断点:互联网进化启示录
[美]杰夫·斯蒂贝尔 / 师蓉 / 中国人民大学出版社有限公司 / 2014-11-1 / CNY 49.00
一部神经学、生物学与互联网技术大融合的互联网进化史诗巨著。 我们正置身网络革命中。互联网的每一丝变化都与你我息息相关。当科技变得无处不在时,它就会改变你我。在《断点》一书中,大脑科学家和企业家杰夫·斯蒂贝尔将带领读者来到大脑、生物与技术的交汇处,向读者展示生物学和神经学是如何与互联网技术发生联系的;我们是如何通过生物学上的前车之鉴,来预测互联网的发展的;互联网在经历增长、断点和平衡后又会发生......一起来看看 《断点:互联网进化启示录》 这本书的介绍吧!
SHA 加密
SHA 加密工具
HEX HSV 转换工具
HEX HSV 互换工具