Add homelab service and system health monitoring

This commit is contained in:
Maxim
2026-08-01 12:02:09 +03:00
parent ad8972320d
commit 980f69cf8f
11 changed files with 674 additions and 33 deletions

84
system_health.go Normal file
View File

@@ -0,0 +1,84 @@
package main
import (
"os/exec"
"strconv"
"strings"
"sync"
"time"
)
type SystemIssue struct {
Time int64 `json:"time"`
Unit string `json:"unit"`
Priority string `json:"priority"`
Message string `json:"message"`
}
type SystemHealthMetrics struct {
Available bool `json:"available"`
FailedUnits int `json:"failedUnits"`
KernelErrors int `json:"kernelErrors"`
SystemErrors int `json:"systemErrors"`
Issues []SystemIssue `json:"issues"`
CheckedAt int64 `json:"checkedAt"`
}
type systemHealthCollector struct {
mu sync.RWMutex
value SystemHealthMetrics
}
func newSystemHealthCollector() *systemHealthCollector {
c := &systemHealthCollector{}
go c.run()
return c
}
func (c *systemHealthCollector) collect() SystemHealthMetrics {
c.mu.RLock()
defer c.mu.RUnlock()
return c.value
}
func (c *systemHealthCollector) run() {
c.refresh()
t := time.NewTicker(time.Minute)
defer t.Stop()
for range t.C {
c.refresh()
}
}
func (c *systemHealthCollector) refresh() {
m := SystemHealthMetrics{CheckedAt: time.Now().Unix()}
if _, err := exec.LookPath("journalctl"); err != nil {
c.mu.Lock()
c.value = m
c.mu.Unlock()
return
}
m.Available = true
if out, err := exec.Command("systemctl", "--failed", "--no-legend", "--plain").Output(); err == nil {
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
if strings.TrimSpace(line) != "" {
m.FailedUnits++
}
}
}
out, _ := exec.Command("journalctl", "--since", "24 hours ago", "-p", "0..3", "--no-pager", "-o", "short-unix", "-n", "100").Output()
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
f := strings.Fields(line)
if len(f) < 2 {
continue
}
raw := strings.TrimSuffix(f[0], ":")
sec, _ := strconv.ParseFloat(raw, 64)
unit := strings.TrimSuffix(f[1], ":")
message := strings.Join(f[2:], " ")
issue := SystemIssue{Time: int64(sec), Unit: unit, Priority: "error", Message: message}
m.Issues = append(m.Issues, issue)
m.SystemErrors++
if strings.Contains(strings.ToLower(unit), "kernel") {
m.KernelErrors++
}
}
c.mu.Lock()
c.value = m
c.mu.Unlock()
}