From f785c0044c7f03084b6a06dfdf8866dcd8a96444 Mon Sep 17 00:00:00 2001 From: Akizon77 Date: Sat, 12 Apr 2025 22:50:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(monitoring):=20=E5=A2=9E=E5=8A=A0=E7=BD=91?= =?UTF-8?q?=E7=BB=9C=E6=80=BB=E9=87=8F=E5=92=8C=E8=BF=9B=E7=A8=8B=E8=AE=A1?= =?UTF-8?q?=E6=95=B0=E7=9B=91=E6=8E=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 net.go 中添加总量统计功能,记录上次采样值 - 在 main.go 中添加进程计数监控 - 修改 remote.go 中的 JSON 字段名称 - 优化 report 函数,增加网络总量和进程计数数据 --- config/remote.go | 6 ++-- main.go | 23 ++++++++++--- monitoring/net.go | 21 ++++++++---- monitoring/process.go | 77 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 14 deletions(-) create mode 100644 monitoring/process.go diff --git a/config/remote.go b/config/remote.go index 0579b68..a0db34b 100644 --- a/config/remote.go +++ b/config/remote.go @@ -16,10 +16,10 @@ type RemoteConfig struct { Swap bool `json:"swap"` Load bool `json:"load"` Uptime bool `json:"uptime"` - Temperature bool `json:"temperature"` + Temperature bool `json:"temp"` Os bool `json:"os"` Disk bool `json:"disk"` - Network bool `json:"network"` + Network bool `json:"net"` Process bool `json:"process"` Interval int `json:"interval"` Connections bool `json:"connections"` @@ -38,7 +38,7 @@ func LoadRemoteConfig(endpoint string, token string) (RemoteConfig, error) { var err error for attempt := 1; attempt <= maxRetry; attempt++ { - resp, err = http.Get(endpoint,) + resp, err = http.Get(endpoint) if err == nil && resp.StatusCode == http.StatusOK { break } diff --git a/main.go b/main.go index 0d8b79d..d57694e 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "encoding/json" "fmt" + "io" "komari/config" "komari/monitoring" "log" @@ -181,8 +182,14 @@ func uploadBasicInfo(endpoint string, token string) error { } defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + message := string(body) + if resp.StatusCode != http.StatusOK { - return fmt.Errorf("status code: %d", resp.StatusCode) + return fmt.Errorf("status code: %d,%s", resp.StatusCode, message) } return nil @@ -229,13 +236,15 @@ func report(localConfig config.LocalConfig, remoteConfig config.RemoteConfig) [] } } if remoteConfig.Network { - networkUp, networkDown, err := monitoring.NetworkSpeed() + totalUp, totalDown, networkUp, networkDown, err := monitoring.NetworkSpeed(remoteConfig.Interval) if err != nil { message += fmt.Sprintf("failed to get network speed: %v\n", err) } data["network"] = map[string]interface{}{ - "up": networkUp, - "down": networkDown, + "up": networkUp, + "down": networkDown, + "totalUp": totalUp, + "totalDown": totalDown, } } if remoteConfig.Connections { @@ -243,7 +252,7 @@ func report(localConfig config.LocalConfig, remoteConfig config.RemoteConfig) [] if err != nil { message += fmt.Sprintf("failed to get connections: %v\n", err) } - data["network"] = map[string]interface{}{ + data["connections"] = map[string]interface{}{ "tcp": tcpCount, "udp": udpCount, } @@ -255,6 +264,10 @@ func report(localConfig config.LocalConfig, remoteConfig config.RemoteConfig) [] } data["uptime"] = uptime } + if remoteConfig.Process { + processcount := monitoring.ProcessCount() + data["process"] = processcount + } data["message"] = message s, err := json.Marshal(data) diff --git a/monitoring/net.go b/monitoring/net.go index 1db950c..735d508 100644 --- a/monitoring/net.go +++ b/monitoring/net.go @@ -19,15 +19,20 @@ func ConnectionsCount() (tcpCount, udpCount int, err error) { return len(tcps), len(udps), nil } -func NetworkSpeed() (upSpeed, downSpeed float64, err error) { +var ( + lastUp uint64 + lastDown uint64 +) + +func NetworkSpeed(interval int) (totalUp, totalDown, upSpeed, downSpeed uint64, err error) { // Get the network IO counters ioCounters, err := net.IOCounters(false) if err != nil { - return 0, 0, fmt.Errorf("failed to get network IO counters: %w", err) + return 0, 0, 0, 0, fmt.Errorf("failed to get network IO counters: %w", err) } if len(ioCounters) == 0 { - return 0, 0, fmt.Errorf("no network interfaces found") + return 0, 0, 0, 0, fmt.Errorf("no network interfaces found") } for _, interfaceStats := range ioCounters { @@ -42,10 +47,14 @@ func NetworkSpeed() (upSpeed, downSpeed float64, err error) { if isLoopback { continue // Skip loopback interface } - upSpeed += float64(interfaceStats.BytesSent) / float64(interfaceStats.PacketsSent) - downSpeed += float64(interfaceStats.BytesRecv) / float64(interfaceStats.PacketsRecv) + totalUp += interfaceStats.BytesSent + totalDown += interfaceStats.BytesRecv } + upSpeed = (totalUp - lastUp) / uint64(interval) + downSpeed = (totalDown - lastDown) / uint64(interval) - return upSpeed, downSpeed, nil + lastUp = totalUp + lastDown = totalDown + return totalUp, totalDown, upSpeed, downSpeed, nil } diff --git a/monitoring/process.go b/monitoring/process.go new file mode 100644 index 0000000..83d814f --- /dev/null +++ b/monitoring/process.go @@ -0,0 +1,77 @@ +package monitoring + +import ( + "os" + "runtime" + "strconv" + "syscall" + "unsafe" +) + +// ProcessCount returns the number of running processes +func ProcessCount() (count int) { + if runtime.GOOS == "windows" { + return processCountWindows() + } + return processCountLinux() +} + +// processCountLinux counts processes by reading /proc directory +func processCountLinux() (count int) { + procDir := "/proc" + + entries, err := os.ReadDir(procDir) + if err != nil { + return 0 + } + + for _, entry := range entries { + if _, err := strconv.ParseInt(entry.Name(), 10, 64); err == nil { + //if _, err := filepath.ParseInt(entry.Name(), 10, 64); err == nil { + count++ + } + } + + return count +} + +// processCountWindows counts processes using Windows API +func processCountWindows() (count int) { + // Load kernel32.dll + kernel32, err := syscall.LoadLibrary("kernel32.dll") + if err != nil { + return 0 + } + defer syscall.FreeLibrary(kernel32) + + // Get EnumProcesses function + enumProcesses, err := syscall.GetProcAddress(kernel32, "K32EnumProcesses") + if err != nil { + return 0 + } + + // Prepare buffer for process IDs + const maxProcesses = 1024 + pids := make([]uint32, maxProcesses) + var bytesReturned uint32 + + // Call EnumProcesses + ret, _, _ := syscall.SyscallN( + uintptr(enumProcesses), + uintptr(unsafe.Pointer(&pids[0])), + uintptr(len(pids)*4), + uintptr(unsafe.Pointer(&bytesReturned)), + ) + + if ret == 0 { + return 0 + } + + // Count valid PIDs + count = int(bytesReturned) / 4 // bytesReturned is size in bytes, divide by 4 for uint32 count + if count > maxProcesses { + count = maxProcesses + } + + return count +}