package collector import ( "os/exec" "strconv" "strings" "time" ) type CPUInfo struct { Model string `json:"model"` Cores int `json:"cores"` Threads int `json:"threads"` FreqMHz int `json:"freq_mhz"` UsagePercent float64 `json:"usage_percent"` } func CollectCPU() CPUInfo { info := CPUInfo{} // CPU Model info.Model = sysctlGet("hw.model") // Anzahl CPUs (Threads) if v, err := strconv.Atoi(sysctlGet("hw.ncpu")); err == nil { info.Threads = v } // Kerne - versuche kern.smp.cores, Fallback auf ncpu if v, err := strconv.Atoi(sysctlGet("kern.smp.cores")); err == nil && v > 0 { info.Cores = v } else { info.Cores = info.Threads } // Frequenz in MHz if v, err := strconv.Atoi(sysctlGet("dev.cpu.0.freq")); err == nil { info.FreqMHz = v } // CPU-Auslastung via kern.cp_time (zwei Messungen im Abstand von 1 Sekunde) info.UsagePercent = measureCPUUsage() return info } func sysctlGet(key string) string { out, err := exec.Command("sysctl", "-n", key).Output() if err != nil { return "" } return strings.TrimSpace(string(out)) } // measureCPUUsage misst die CPU-Auslastung ueber kern.cp_time // Format: user nice sys intr idle func measureCPUUsage() float64 { parse := func() (idle, total int64, ok bool) { out := sysctlGet("kern.cp_time") if out == "" { return 0, 0, false } fields := strings.Fields(out) if len(fields) < 5 { return 0, 0, false } var vals [5]int64 for i := 0; i < 5; i++ { v, err := strconv.ParseInt(fields[i], 10, 64) if err != nil { return 0, 0, false } vals[i] = v } // user + nice + sys + intr + idle total = vals[0] + vals[1] + vals[2] + vals[3] + vals[4] idle = vals[4] return idle, total, true } idle1, total1, ok1 := parse() if !ok1 { return 0 } time.Sleep(1 * time.Second) idle2, total2, ok2 := parse() if !ok2 { return 0 } totalDelta := float64(total2 - total1) if totalDelta == 0 { return 0 } idleDelta := float64(idle2 - idle1) usage := (1.0 - idleDelta/totalDelta) * 100.0 if usage < 0 { usage = 0 } if usage > 100 { usage = 100 } return usage }