Golang实践录:获取系统信息

Posted 李迟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang实践录:获取系统信息相关的知识,希望对你有一定的参考价值。

本文介绍获取系统信息的方法,另外给出根据不同系统编译的方法。

问题提出

由于多年来接触了不同系统的兼容工程,对使用宏区分不同的代码一直有一种莫名的感觉。像 Linux 内核中就有很多这样的代码,coreboot 中有,nRF52 SDK中也有。在实现的工程库也要往这方向考虑,比如线程库和socket库。当接触 golang 后,因其跨平台,编码快,所以在工作中也使用了。但并不是所有代码都是跨平台,像 syscall这样的包,就无法做到。最近的工程中需要获取系统信息,但无法只使用 golang 官方的接口达到目的,最终找到了第三方库github.com/shirou/gopsutil

在找到第三方库前,也想过根据不同的系统编译不同的源码文件,经过考量,还是直接用现成的库。

golang 的编译选项

在进入主题前,先了解一下编译选项。C++可以直接在文件开始和结束处分别加#if 0#endif解决,相应的,golang 可以在.go文件定义包前添加// +build windows// +build linux来区别在哪个系统编译。

如果后面跟着注释,会提示//go:build comment without // +build comment

另一种方法,是直接使用源码文件名称来区分。比如ccall_linux.goccall_windows.go分别在 Linux 系统和 Windows 系统下编译,这种方法非常直观。golang 中带_test的文件是测试用例,这其中的设计思想是一致的。

实际中,笔者使用的工程会调用 Linux 的动态库,但在编译调试时,还是以 Windows 为主,因为涉及 web 前端的设计,这样就可以在 Windows 中不调用动态库,即接口函数做空实现。

获取系统信息

gopsutil 抽象了不同系统,提供统一接口,因为不存在上述问题,本节给出一些示例代码,可以获取一些必要的系统信息,如CPU、内存、磁盘等。

package gin

import (
	"fmt"
	"os"
	"runtime"
	"time"

	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/host"
	"github.com/shirou/gopsutil/net"
	"github.com/shirou/gopsutil/v3/mem"
)

type LSysInfo struct 
	MemAll         uint64
	MemFree        uint64
	MemUsed        uint64
	MemUsedPercent float64
	Days           int64
	Hours          int64
	Minutes        int64
	Seconds        int64

	CpuUsedPercent float64
	OS             string
	Arch           string
	CpuCores       int


func GetSysInfo() (info LSysInfo) 
	unit := uint64(1024 * 1024) // MB

	v, _ := mem.VirtualMemory()

	info.MemAll = v.Total
	info.MemFree = v.Free
	info.MemUsed = info.MemAll - info.MemFree
	// 注:使用SwapMemory或VirtualMemory,在不同系统中使用率不一样,因此直接计算一次
	info.MemUsedPercent = float64(info.MemUsed) / float64(info.MemAll) * 100.0 // v.UsedPercent
	info.MemAll /= unit
	info.MemUsed /= unit
	info.MemFree /= unit

	info.OS = runtime.GOOS
	info.Arch = runtime.GOARCH
	info.CpuCores = runtime.GOMAXPROCS(0)

	// 获取200ms内的CPU信息,太短不准确,也可以获几秒内的,但这样会有延时,因为要等待
	cc, _ := cpu.Percent(time.Millisecond*200, false)
	info.CpuUsedPercent = cc[0]

	// 获取开机时间
	boottime, _ := host.BootTime()
	ntime := time.Now().Unix()
	btime := time.Unix(int64(boottime), 0).Unix()
	deltatime := ntime - btime

	info.Seconds = int64(deltatime)
	info.Minutes = info.Seconds / 60
	info.Seconds -= info.Minutes * 60
	info.Hours = info.Minutes / 60
	info.Minutes -= info.Hours * 60
	info.Days = info.Hours / 24
	info.Hours -= info.Days * 24

	fmt.Printf("info: %#v\\n", info)

	infoTest()
	os.Exit(0)
	return


func infoTest() 
	c, _ := cpu.Info()
	cc, _ := cpu.Percent(time.Second, false) // 1秒
	d, _ := disk.Usage("/")
	n, _ := host.Info()
	nv, _ := net.IOCounters(true)
	physicalCnt, _ := cpu.Counts(false)
	logicalCnt, _ := cpu.Counts(true)
	if len(c) > 1 
		for _, sub_cpu := range c 
			modelname := sub_cpu.ModelName
			cores := sub_cpu.Cores
			fmt.Printf("CPUs: %v   %v cores \\n", modelname, cores)
		
	 else 
		sub_cpu := c[0]
		modelname := sub_cpu.ModelName
		cores := sub_cpu.Cores
		fmt.Printf("CPU: %v   %v cores \\n", modelname, cores)
	
	fmt.Printf("physical count:%d logical count:%d\\n", physicalCnt, logicalCnt)
	fmt.Printf("CPU Used: used %f%%\\n", cc[0])
	fmt.Printf("HD: %v GB Free: %v GB Usage:%f%%\\n", d.Total/1024/1024/1024, d.Free/1024/1024/1024, d.UsedPercent)
	fmt.Printf("OS: %v(%v) %v\\n", n.Platform, n.PlatformFamily, n.PlatformVersion)
	fmt.Printf("Hostname: %v\\n", n.Hostname)
	fmt.Printf("Network: %v bytes / %v bytes\\n", nv[0].BytesRecv, nv[0].BytesSent)

需要注意的,计算内存的使用率,是根据已获取的已用内存除以总内存,而不是直接由gopsutil获取。计算CPU使用率,需要指定时间间隔,如果秒级别,用户会感觉卡顿,文中代码使用 200 毫秒,经测试,有时获取的值为0。至于运行时间,则通过时间戳直接计算出天数。

某windows系统运行结果如下:

info: gin.LSysInfoMemAll:0x2ec6, MemFree:0x11a5, MemUsed:0x1d21, MemUsedPercent:62.27692697126946, Days:0, Hours:9, Minutes:26, Seconds:6, CpuUsedPercent:5.882352941068881, OS:"windows", Arch:"amd64", CpuCores:4
CPU: Intel(R) Core(TM) i5-4210M CPU @ 2.60GHz   4 cores
physical count:2 logical count:4
CPU Used: used 8.593750%
HD: 330 GB Free: 32 GB Usage:90.242198%
OS: Microsoft Windows 7 Ultimate Service Pack 1(Standalone Workstation) 6.1.7601 Build 7601
Hostname: SKY-20210126BVC
Network: 0 bytes / 0 bytes

某 linux 服务器运行结果:

info: gin.LSysInfoMemAll:0xf84b, MemFree:0x527, MemUsed:0xf323, MemUsedPercent:97.92430801663596, Days:0, Hours:1, Minutes:6, Seconds:38, CpuUsedPercent:0.25062656021506197, OS:"linux", Arch:"amd64", CpuCores:20
CPUs: Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz   1 cores 
CPUs: Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz   1 cores 
...
physical count:10 logical count:20
CPU Used: used 0.702459%
HD: 49 GB Free: 38 GB Usage:16.708842%
OS: centos(rhel) 7.6.000
Hostname: localhost.localdomain
Network: 1915935 bytes / 224926648 bytes

以上是关于Golang实践录:获取系统信息的主要内容,如果未能解决你的问题,请参考以下文章

Golang实践录:获取目录文件列表

Golang实践录:获取目录文件列表

Golang实践录:获取目录文件列表

Golang实践录:调用C++函数的优化

Golang实践录:使用gin实现http basic认证

Golang实践录:map的几个使用示例