feat: multi-percentage monitors (per-core CPU), max 8

This commit is contained in:
Pi Agent
2026-09-02 16:13:36 +00:00
parent 4f98490224
commit 887d45a771
9 changed files with 112 additions and 41 deletions
+29 -18
View File
@@ -30,9 +30,10 @@ type Item struct {
}
type Monitor struct {
Name string `yaml:"name"`
Script string `yaml:"script"`
Refresh int `yaml:"refresh"` // seconds
Name string `yaml:"name"`
Script string `yaml:"script"`
Refresh int `yaml:"refresh"` // seconds
Percentages int `yaml:"percentages"` // сколько процентных строк отдает скрипт (1..8); 0 = 1
}
type Link struct {
@@ -54,24 +55,31 @@ type server struct {
const execTimeout = 10 * time.Second
// monData — распарсенный вывод скрипта-монитора: первая строка — процент,
// остальные — строки key=value для подписей в карточке.
// monData — распарсенный вывод скрипта-монитора: первые строки-проценты
// (первая — основной процент карточки), остальные — key=value для подписей.
type monData struct {
percentage int32 // -1 = скрипт не дал процент
stats []*homelabv1.Stat
percentage int32 // -1 = скрипт не дал процент
percentages []int32 // все проценты (основной + дополнительные, max 8)
stats []*homelabv1.Stat
}
func parseMonitor(out string) *monData {
func parseMonitor(out string, maxPct int) *monData {
d := &monData{percentage: -1}
lines := strings.Split(strings.TrimSpace(out), "\n")
if lines[0] == "" {
return d
}
if n, err := strconv.Atoi(strings.TrimSpace(lines[0])); err == nil {
d.percentage = int32(n)
}
for _, l := range lines[1:] {
if k, v, ok := strings.Cut(strings.TrimSpace(l), "="); ok {
for i, l := range strings.Split(strings.TrimSpace(out), "\n") {
l = strings.TrimSpace(l)
if l == "" {
continue
}
if i < maxPct {
if n, err := strconv.Atoi(l); err == nil {
if len(d.percentages) == 0 {
d.percentage = int32(n)
}
d.percentages = append(d.percentages, int32(n))
continue
}
}
if k, v, ok := strings.Cut(l, "="); ok {
d.stats = append(d.stats, &homelabv1.Stat{Name: strings.TrimSpace(k), Value: strings.TrimSpace(v)})
}
}
@@ -99,7 +107,10 @@ func (s *server) startMonitors() {
log.Printf("monitor %s: %v", sc.Name, err)
out = "-\nerror=" + err.Error()
}
d := parseMonitor(out)
if sc.Percentages < 1 {
sc.Percentages = 1
}
d := parseMonitor(out, sc.Percentages)
log.Printf("monitor %s -> %d%% (%d stats)", sc.Name, d.percentage, len(d.stats))
s.monVals.Store(sc.Name, d)
time.Sleep(time.Duration(sc.Refresh) * time.Second)