package collector import ( "os" "strconv" "strings" "time" ) type CPUInfo struct { Model string Cores int Threads int FreqMHz int UsagePercent float64 } func CollectCPU() CPUInfo { cpu := CPUInfo{} // CPU-Informationen aus /proc/cpuinfo lesen if data, err := os.ReadFile("/proc/cpuinfo"); err == nil { lines := strings.Split(string(data), "\n") cpuCount := 0 for _, line := range lines { line = strings.TrimSpace(line) if line == "" { continue } parts := strings.SplitN(line, ":", 2) if len(parts) != 2 { continue } key := strings.TrimSpace(parts[0]) value := strings.TrimSpace(parts[1]) switch key { case "model name": if cpu.Model == "" { // Nur vom ersten CPU nehmen cpu.Model = value } case "cpu MHz": if cpu.FreqMHz == 0 { // Nur vom ersten CPU nehmen if freq, err := strconv.ParseFloat(value, 64); err == nil { cpu.FreqMHz = int(freq) } } case "processor": cpuCount++ case "cpu cores": if cores, err := strconv.Atoi(value); err == nil && cpu.Cores == 0 { cpu.Cores = cores } case "siblings": if threads, err := strconv.Atoi(value); err == nil && cpu.Threads == 0 { cpu.Threads = threads } } } // Falls cpu cores und siblings nicht vorhanden, nutze processor count if cpu.Cores == 0 { cpu.Cores = cpuCount } if cpu.Threads == 0 { cpu.Threads = cpuCount } } // CPU-Usage berechnen cpu.UsagePercent = calculateCPUUsage() return cpu } // Berechnet die aktuelle CPU-Auslastung über zwei /proc/stat Messungen func calculateCPUUsage() float64 { stat1 := readCPUStat() if stat1 == nil { return 0.0 } time.Sleep(100 * time.Millisecond) // Kurz warten für zweite Messung stat2 := readCPUStat() if stat2 == nil { return 0.0 } // Delta berechnen totalDelta := (stat2.total - stat1.total) idleDelta := (stat2.idle - stat1.idle) if totalDelta <= 0 { return 0.0 } usage := 100.0 * float64(totalDelta-idleDelta) / float64(totalDelta) if usage < 0 { usage = 0 } if usage > 100 { usage = 100 } return usage } type cpuStat struct { total int64 idle int64 } // Liest CPU-Statistiken aus /proc/stat func readCPUStat() *cpuStat { data, err := os.ReadFile("/proc/stat") if err != nil { return nil } lines := strings.Split(string(data), "\n") if len(lines) == 0 { return nil } // Erste Zeile sollte "cpu ..." sein firstLine := strings.TrimSpace(lines[0]) if !strings.HasPrefix(firstLine, "cpu ") { return nil } fields := strings.Fields(firstLine) if len(fields) < 5 { return nil } // cpu user nice system idle iowait irq softirq ... var values []int64 for i := 1; i < len(fields) && i <= 7; i++ { // max 7 Werte lesen if val, err := strconv.ParseInt(fields[i], 10, 64); err == nil { values = append(values, val) } } if len(values) < 4 { return nil } // Total = Summe aller Werte total := int64(0) for _, val := range values { total += val } // Idle = idle + iowait (falls iowait verfügbar) idle := values[3] // idle if len(values) > 4 { idle += values[4] // + iowait } return &cpuStat{ total: total, idle: idle, } }