zlh-agent/internal/metrics/process.go
2026-03-07 20:59:27 +00:00

104 lines
2.0 KiB
Go

package metrics
import (
"bufio"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"zlh-agent/internal/state"
"zlh-agent/internal/system"
)
type ProcessSection struct {
PID int `json:"pid"`
Status string `json:"status"`
UptimeSeconds *int64 `json:"uptime_seconds"`
RestartCount int `json:"restart_count"`
}
type MemorySection struct {
RSSBytes int64 `json:"rss_bytes"`
VMSBytes int64 `json:"vms_bytes"`
}
type ProcessMetricsResponse struct {
Process ProcessSection `json:"process"`
Memory MemorySection `json:"memory"`
}
func ProcessMetrics() (ProcessMetricsResponse, bool, error) {
pid, ok := system.GetServerPID()
if !ok {
return ProcessMetricsResponse{
Process: ProcessSection{
PID: 0,
Status: "stopped",
RestartCount: state.GetCrashCount(),
},
}, true, nil
}
rss, vms, err := readMemoryFromStatus(pid)
if err != nil {
return ProcessMetricsResponse{}, false, err
}
return ProcessMetricsResponse{
Process: ProcessSection{
PID: pid,
Status: "running",
UptimeSeconds: nil,
RestartCount: state.GetCrashCount(),
},
Memory: MemorySection{
RSSBytes: rss,
VMSBytes: vms,
},
}, false, nil
}
func readMemoryFromStatus(pid int) (int64, int64, error) {
statusPath := filepath.Join("/proc", strconv.Itoa(pid), "status")
f, err := os.Open(statusPath)
if err != nil {
return 0, 0, err
}
defer f.Close()
var rssKB int64
var vmsKB int64
s := bufio.NewScanner(f)
for s.Scan() {
line := s.Text()
if strings.HasPrefix(line, "VmRSS:") {
rssKB = parseKBLine(line)
}
if strings.HasPrefix(line, "VmSize:") {
vmsKB = parseKBLine(line)
}
}
if err := s.Err(); err != nil {
return 0, 0, err
}
if rssKB == 0 && vmsKB == 0 {
return 0, 0, fmt.Errorf("missing VmRSS/VmSize in %s", statusPath)
}
return rssKB * 1024, vmsKB * 1024, nil
}
func parseKBLine(line string) int64 {
fields := strings.Fields(line)
if len(fields) < 2 {
return 0
}
n, err := strconv.ParseInt(fields[1], 10, 64)
if err != nil {
return 0
}
return n
}