feat: multi-percentage monitors (per-core CPU), max 8
This commit is contained in:
@@ -47,6 +47,9 @@ func loadConfig(path string) (*Config, error) {
|
||||
if it.Refresh <= 0 {
|
||||
return nil, fmt.Errorf("monitor %q: refresh must be > 0", it.Name)
|
||||
}
|
||||
if it.Percentages < 0 || it.Percentages > 8 {
|
||||
return nil, fmt.Errorf("monitor %q: percentages must be 1..8", it.Name)
|
||||
}
|
||||
}
|
||||
for _, it := range cfg.Exec {
|
||||
if len(it.ArgTypes) != it.Args {
|
||||
|
||||
+29
-18
@@ -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)
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ func (s *server) ListContent(ctx context.Context, _ *connect.Request[homelabv1.L
|
||||
m := &homelabv1.Monitor{Name: it.Name}
|
||||
if d, ok := s.monVals.Load(it.Name); ok {
|
||||
md := d.(*monData)
|
||||
m.Percentage, m.Stats = md.percentage, md.stats
|
||||
m.Percentage, m.Percentages, m.Stats = md.percentage, md.percentages, md.stats
|
||||
}
|
||||
resp.Monitors = append(resp.Monitors, m)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user