package agent import ( "bufio" "os" "strconv" "strings" "time" ) // nowTS возвращает текущий unix timestamp. func nowTS() int64 { return time.Now().Unix() } // SystemStats содержит системные метрики (CPU, load). type SystemStats struct { Load1 float64 // load average 1m Load5 float64 // load average 5m Load15 float64 // load average 15m IdleCPU float64 // процент простоя CPU } // CollectSystem собирает системные метрики из /proc. func CollectSystem() *SystemStats { load1, load5, load15 := loadAvg() return &SystemStats{ Load1: load1, Load5: load5, Load15: load15, IdleCPU: cpuIdle(), } } // loadAvg читает /proc/loadavg. func loadAvg() (float64, float64, float64) { data, err := os.ReadFile("/proc/loadavg") if err != nil { return 0, 0, 0 } parts := strings.Fields(string(data)) if len(parts) < 3 { return 0, 0, 0 } load1, _ := strconv.ParseFloat(parts[0], 64) load5, _ := strconv.ParseFloat(parts[1], 64) load15, _ := strconv.ParseFloat(parts[2], 64) return load1, load5, load15 } // cpuIdle вычисляет процент простоя CPU из /proc/stat. func cpuIdle() float64 { file, err := os.Open("/proc/stat") if err != nil { return 0 } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() if !strings.HasPrefix(line, "cpu ") { continue } fields := strings.Fields(line) if len(fields) < 8 { return 0 } // cpu user nice system idle iowait irq softirq steal ... var total, idle float64 for i, f := range fields[1:] { val, _ := strconv.ParseFloat(f, 64) total += val if i == 3 || i == 4 { // idle + iowait idle += val } } if total > 0 { return (idle / total) * 100.0 } return 0 } return 0 }