110 lines
2.1 KiB
Go
110 lines
2.1 KiB
Go
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
|
|
}
|