feat(monitoring): 增加网络总量和进程计数监控

- 在 net.go 中添加总量统计功能,记录上次采样值
- 在 main.go 中添加进程计数监控
- 修改 remote.go 中的 JSON 字段名称
- 优化 report 函数,增加网络总量和进程计数数据
This commit is contained in:
Akizon77
2025-04-12 22:50:56 +08:00
parent c2a9148d4c
commit f785c0044c
4 changed files with 113 additions and 14 deletions

View File

@@ -16,10 +16,10 @@ type RemoteConfig struct {
Swap bool `json:"swap"` Swap bool `json:"swap"`
Load bool `json:"load"` Load bool `json:"load"`
Uptime bool `json:"uptime"` Uptime bool `json:"uptime"`
Temperature bool `json:"temperature"` Temperature bool `json:"temp"`
Os bool `json:"os"` Os bool `json:"os"`
Disk bool `json:"disk"` Disk bool `json:"disk"`
Network bool `json:"network"` Network bool `json:"net"`
Process bool `json:"process"` Process bool `json:"process"`
Interval int `json:"interval"` Interval int `json:"interval"`
Connections bool `json:"connections"` Connections bool `json:"connections"`
@@ -38,7 +38,7 @@ func LoadRemoteConfig(endpoint string, token string) (RemoteConfig, error) {
var err error var err error
for attempt := 1; attempt <= maxRetry; attempt++ { for attempt := 1; attempt <= maxRetry; attempt++ {
resp, err = http.Get(endpoint,) resp, err = http.Get(endpoint)
if err == nil && resp.StatusCode == http.StatusOK { if err == nil && resp.StatusCode == http.StatusOK {
break break
} }

23
main.go
View File

@@ -4,6 +4,7 @@ import (
"crypto/tls" "crypto/tls"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"komari/config" "komari/config"
"komari/monitoring" "komari/monitoring"
"log" "log"
@@ -181,8 +182,14 @@ func uploadBasicInfo(endpoint string, token string) error {
} }
defer resp.Body.Close() defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
message := string(body)
if resp.StatusCode != http.StatusOK { 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 return nil
@@ -229,13 +236,15 @@ func report(localConfig config.LocalConfig, remoteConfig config.RemoteConfig) []
} }
} }
if remoteConfig.Network { if remoteConfig.Network {
networkUp, networkDown, err := monitoring.NetworkSpeed() totalUp, totalDown, networkUp, networkDown, err := monitoring.NetworkSpeed(remoteConfig.Interval)
if err != nil { if err != nil {
message += fmt.Sprintf("failed to get network speed: %v\n", err) message += fmt.Sprintf("failed to get network speed: %v\n", err)
} }
data["network"] = map[string]interface{}{ data["network"] = map[string]interface{}{
"up": networkUp, "up": networkUp,
"down": networkDown, "down": networkDown,
"totalUp": totalUp,
"totalDown": totalDown,
} }
} }
if remoteConfig.Connections { if remoteConfig.Connections {
@@ -243,7 +252,7 @@ func report(localConfig config.LocalConfig, remoteConfig config.RemoteConfig) []
if err != nil { if err != nil {
message += fmt.Sprintf("failed to get connections: %v\n", err) message += fmt.Sprintf("failed to get connections: %v\n", err)
} }
data["network"] = map[string]interface{}{ data["connections"] = map[string]interface{}{
"tcp": tcpCount, "tcp": tcpCount,
"udp": udpCount, "udp": udpCount,
} }
@@ -255,6 +264,10 @@ func report(localConfig config.LocalConfig, remoteConfig config.RemoteConfig) []
} }
data["uptime"] = uptime data["uptime"] = uptime
} }
if remoteConfig.Process {
processcount := monitoring.ProcessCount()
data["process"] = processcount
}
data["message"] = message data["message"] = message
s, err := json.Marshal(data) s, err := json.Marshal(data)

View File

@@ -19,15 +19,20 @@ func ConnectionsCount() (tcpCount, udpCount int, err error) {
return len(tcps), len(udps), nil 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 // Get the network IO counters
ioCounters, err := net.IOCounters(false) ioCounters, err := net.IOCounters(false)
if err != nil { 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 { 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 { for _, interfaceStats := range ioCounters {
@@ -42,10 +47,14 @@ func NetworkSpeed() (upSpeed, downSpeed float64, err error) {
if isLoopback { if isLoopback {
continue // Skip loopback interface continue // Skip loopback interface
} }
upSpeed += float64(interfaceStats.BytesSent) / float64(interfaceStats.PacketsSent) totalUp += interfaceStats.BytesSent
downSpeed += float64(interfaceStats.BytesRecv) / float64(interfaceStats.PacketsRecv) 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
} }

77
monitoring/process.go Normal file
View File

@@ -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
}