nezha/cmd/agent/monitor/monitor.go

249 lines
6.4 KiB
Go
Raw Normal View History

2019-12-07 05:14:40 -05:00
package monitor
import (
"fmt"
"os/exec"
2021-08-07 22:06:44 -04:00
"runtime"
"strconv"
2019-12-09 03:02:49 -05:00
"strings"
"syscall"
2019-12-07 05:14:40 -05:00
"time"
"github.com/Erope/goss"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/disk"
"github.com/shirou/gopsutil/v3/host"
"github.com/shirou/gopsutil/v3/load"
"github.com/shirou/gopsutil/v3/mem"
"github.com/shirou/gopsutil/v3/net"
"github.com/shirou/gopsutil/v3/process"
2019-12-07 05:14:40 -05:00
2020-11-10 21:07:45 -05:00
"github.com/naiba/nezha/model"
2019-12-07 05:14:40 -05:00
)
var (
Version string
expectDiskFsTypes = []string{
"apfs", "ext4", "ext3", "ext2", "f2fs", "reiserfs", "jfs", "btrfs",
"fuseblk", "zfs", "simfs", "ntfs", "fat32", "exfat", "xfs", "fuse.rclone",
}
excludeNetInterfaces = []string{
"lo", "tun", "docker", "veth", "br-", "vmbr", "vnet", "kube",
}
)
var (
netInSpeed, netOutSpeed, netInTransfer, netOutTransfer, lastUpdateNetStats uint64
cachedBootTime time.Time
)
2021-03-19 22:05:16 -04:00
// GetHost 获取主机硬件信息
2022-03-19 05:22:15 -04:00
func GetHost(agentConfig *model.AgentConfig) *model.Host {
2019-12-07 05:14:40 -05:00
hi, _ := host.Info()
2021-02-27 06:24:19 -05:00
var cpuType string
if hi.VirtualizationSystem != "" {
2022-04-10 08:28:22 -04:00
cpuType = "Virtual"
2021-02-27 06:24:19 -05:00
} else {
cpuType = "Physical"
}
cpuModelCount := make(map[string]int)
2019-12-07 05:14:40 -05:00
ci, _ := cpu.Info()
for i := 0; i < len(ci); i++ {
2021-02-27 06:24:19 -05:00
cpuModelCount[ci[i].ModelName]++
}
var cpus []string
for model, count := range cpuModelCount {
cpus = append(cpus, fmt.Sprintf("%s %d %s Core", model, count, cpuType))
2019-12-07 05:14:40 -05:00
}
2019-12-11 08:50:49 -05:00
mv, _ := mem.VirtualMemory()
2022-03-19 05:22:15 -04:00
diskTotal, _ := getDiskTotalAndUsed(agentConfig)
2021-03-19 22:05:16 -04:00
2021-08-07 22:06:44 -04:00
var swapMemTotal uint64
if runtime.GOOS == "windows" {
ms, _ := mem.SwapMemory()
swapMemTotal = ms.Total
} else {
swapMemTotal = mv.SwapTotal
}
if cachedBootTime.IsZero() {
cachedBootTime = time.Unix(int64(hi.BootTime), 0)
}
2019-12-07 05:14:40 -05:00
return &model.Host{
Platform: hi.OS,
PlatformVersion: hi.PlatformVersion,
CPU: cpus,
2019-12-11 08:50:49 -05:00
MemTotal: mv.Total,
2021-08-07 22:06:44 -04:00
SwapTotal: swapMemTotal,
DiskTotal: diskTotal,
2019-12-07 05:14:40 -05:00
Arch: hi.KernelArch,
Virtualization: hi.VirtualizationSystem,
2019-12-09 10:45:23 -05:00
BootTime: hi.BootTime,
2021-03-19 22:05:16 -04:00
IP: cachedIP,
2021-03-20 11:50:16 -04:00
CountryCode: strings.ToLower(cachedCountry),
2021-07-08 12:01:58 -04:00
Version: Version,
2019-12-07 05:14:40 -05:00
}
}
2022-03-19 05:22:15 -04:00
func GetState(agentConfig *model.AgentConfig, skipConnectionCount bool, skipProcsCount bool) *model.HostState {
var procs []int32
if !skipProcsCount {
procs, _ = process.Pids()
}
2019-12-07 05:14:40 -05:00
mv, _ := mem.VirtualMemory()
2021-08-07 22:06:44 -04:00
var swapMemUsed uint64
if runtime.GOOS == "windows" {
// gopsutil 在 Windows 下不能正确取 swap
2021-08-07 22:06:44 -04:00
ms, _ := mem.SwapMemory()
swapMemUsed = ms.Used
} else {
swapMemUsed = mv.SwapTotal - mv.SwapFree
}
2019-12-09 10:45:23 -05:00
var cpuPercent float64
cp, err := cpu.Percent(0, false)
2019-12-09 10:45:23 -05:00
if err == nil {
cpuPercent = cp[0]
}
2022-03-19 05:22:15 -04:00
_, diskUsed := getDiskTotalAndUsed(agentConfig)
loadStat, _ := load.Avg()
var tcpConnCount, udpConnCount uint64
2021-09-27 09:18:09 -04:00
if !skipConnectionCount {
ss_err := true
if runtime.GOOS == "linux" {
tcpStat, err_tcp := goss.ConnectionsWithProtocol(syscall.IPPROTO_TCP)
udpStat, err_udp := goss.ConnectionsWithProtocol(syscall.IPPROTO_UDP)
if err_tcp == nil && err_udp == nil {
ss_err = false
tcpConnCount = uint64(len(tcpStat))
udpConnCount = uint64(len(udpStat))
}
}
if ss_err {
conns, _ := net.Connections("all")
for i := 0; i < len(conns); i++ {
switch conns[i].Type {
case syscall.SOCK_STREAM:
tcpConnCount++
case syscall.SOCK_DGRAM:
udpConnCount++
}
}
}
}
return &model.HostState{
2019-12-09 10:45:23 -05:00
CPU: cpuPercent,
MemUsed: mv.Total - mv.Available,
2021-08-07 22:06:44 -04:00
SwapUsed: swapMemUsed,
DiskUsed: diskUsed,
NetInTransfer: netInTransfer,
NetOutTransfer: netOutTransfer,
NetInSpeed: netInSpeed,
NetOutSpeed: netOutSpeed,
Uptime: uint64(time.Since(cachedBootTime).Seconds()),
Load1: loadStat.Load1,
Load5: loadStat.Load5,
Load15: loadStat.Load15,
TcpConnCount: tcpConnCount,
UdpConnCount: udpConnCount,
ProcessCount: uint64(len(procs)),
2019-12-07 05:14:40 -05:00
}
2019-12-09 10:45:23 -05:00
}
// TrackNetworkSpeed NIC监控统计流量与速度
2022-03-19 05:22:15 -04:00
func TrackNetworkSpeed(agentConfig *model.AgentConfig) {
2019-12-09 10:45:23 -05:00
var innerNetInTransfer, innerNetOutTransfer uint64
nc, err := net.IOCounters(true)
2019-12-07 05:14:40 -05:00
if err == nil {
for _, v := range nc {
2022-03-19 05:22:15 -04:00
if len(agentConfig.NICAllowlist) > 0 {
if !agentConfig.NICAllowlist[v.Name] {
continue
}
} else {
if isListContainsStr(excludeNetInterfaces, v.Name) {
continue
}
}
innerNetInTransfer += v.BytesRecv
innerNetOutTransfer += v.BytesSent
}
2019-12-13 01:51:51 -05:00
now := uint64(time.Now().Unix())
diff := now - lastUpdateNetStats
2019-12-09 10:45:23 -05:00
if diff > 0 {
netInSpeed = (innerNetInTransfer - netInTransfer) / diff
netOutSpeed = (innerNetOutTransfer - netOutTransfer) / diff
2019-12-09 10:45:23 -05:00
}
netInTransfer = innerNetInTransfer
netOutTransfer = innerNetOutTransfer
lastUpdateNetStats = now
2019-12-07 05:14:40 -05:00
}
}
2022-03-19 05:22:15 -04:00
func getDiskTotalAndUsed(agentConfig *model.AgentConfig) (total uint64, used uint64) {
2021-04-26 07:13:02 -04:00
devices := make(map[string]string)
2022-03-19 05:22:15 -04:00
if len(agentConfig.HardDrivePartitionAllowlist) > 0 {
// 如果配置了白名单,使用白名单的列表
for i, v := range agentConfig.HardDrivePartitionAllowlist {
devices[strconv.Itoa(i)] = v
2021-04-26 07:13:02 -04:00
}
2022-03-19 05:22:15 -04:00
} else {
// 否则使用默认过滤规则
diskList, _ := disk.Partitions(false)
for _, d := range diskList {
fsType := strings.ToLower(d.Fstype)
// 不统计 K8s 的虚拟挂载点https://github.com/shirou/gopsutil/issues/1007
if devices[d.Device] == "" && isListContainsStr(expectDiskFsTypes, fsType) && !strings.Contains(d.Mountpoint, "/var/lib/kubelet") {
devices[d.Device] = d.Mountpoint
}
2022-03-19 05:22:15 -04:00
}
}
for _, mountPath := range devices {
diskUsageOf, err := disk.Usage(mountPath)
if err == nil {
2021-04-26 07:13:02 -04:00
total += diskUsageOf.Total
2022-03-19 05:22:15 -04:00
used += diskUsageOf.Used
}
}
// Fallback 到这个方法,仅统计根路径,适用于OpenVZ之类的.
2022-03-19 05:22:15 -04:00
if runtime.GOOS == "linux" && total == 0 && used == 0 {
cmd := exec.Command("df")
out, err := cmd.CombinedOutput()
if err == nil {
s := strings.Split(string(out), "\n")
for _, c := range s {
info := strings.Fields(c)
if len(info) == 6 {
if info[5] == "/" {
total, _ = strconv.ParseUint(info[1], 0, 64)
used, _ = strconv.ParseUint(info[2], 0, 64)
// 默认获取的是1K块为单位的.
total = total * 1024
used = used * 1024
}
}
}
}
}
return
}
2021-04-26 07:13:02 -04:00
func isListContainsStr(list []string, str string) bool {
for i := 0; i < len(list); i++ {
2021-07-16 02:49:15 -04:00
if strings.Contains(str, list[i]) {
2021-04-26 07:13:02 -04:00
return true
}
}
return false
}