rmm2/backend/monitor/monitor.go
cynfo3000 c72b791796 Agent-Status und Inaktivitaets-Erkennung implementiert
- Status wird aus last_heartbeat berechnet (online/stale/offline/unknown)
- GET /agents und GET /agents/{id} liefern status Feld
- agent_events Tabelle fuer Event-Tracking (Migration automatisch)
- Inaktivitaets-Monitor als Goroutine (prueft alle 60s, schreibt Events bei Statuswechsel)
- WebSocket Connect/Disconnect Events werden automatisch geschrieben
- API-Endpoints: GET /agents/events und GET /agents/{id}/events (?limit=N&type=X)
- DB-Methoden: InsertAgentEvent, GetAgentEvents, GetAllAgentEvents, GetAgentStatus
- README aktualisiert (Status-Doku, Events API, Dateistruktur)
2026-02-28 13:13:13 +01:00

78 lines
1.8 KiB
Go

package monitor
import (
"log"
"sync"
"time"
"github.com/cynfo/rmm-backend/db"
"github.com/cynfo/rmm-backend/models"
)
// Monitor prueft periodisch den Agent-Status und schreibt Events bei Statuswechsel
type Monitor struct {
db *db.Database
lastStatus map[string]string
lastStatusMu sync.Mutex
interval time.Duration
}
// New erstellt einen neuen Monitor
func New(database *db.Database) *Monitor {
return &Monitor{
db: database,
lastStatus: make(map[string]string),
interval: 60 * time.Second,
}
}
// Run startet den Monitor als Goroutine — blockiert, also mit go aufrufen
func (m *Monitor) Run() {
log.Println("Inaktivitaets-Monitor gestartet (Intervall: 60s)")
// Initialen Status laden
m.checkAgents()
ticker := time.NewTicker(m.interval)
defer ticker.Stop()
for range ticker.C {
m.checkAgents()
}
}
func (m *Monitor) checkAgents() {
agents, err := m.db.GetAgents()
if err != nil {
log.Printf("Monitor: Fehler beim Laden der Agents: %v", err)
return
}
m.lastStatusMu.Lock()
defer m.lastStatusMu.Unlock()
for _, agent := range agents {
newStatus := models.CalculateAgentStatus(agent.LastHeartbeat)
oldStatus, known := m.lastStatus[agent.ID]
if !known {
// Erster Check — Status merken, kein Event
m.lastStatus[agent.ID] = newStatus
log.Printf("Monitor: Agent %s (%s) initialer Status: %s", agent.Name, agent.ID, newStatus)
continue
}
if oldStatus == newStatus {
continue
}
// Statuswechsel erkannt
log.Printf("Monitor: Agent %s (%s) Status-Wechsel: %s -> %s", agent.Name, agent.ID, oldStatus, newStatus)
m.lastStatus[agent.ID] = newStatus
// Event schreiben
message := "Status-Wechsel: " + oldStatus + " -> " + newStatus
m.db.InsertAgentEvent(agent.ID, newStatus, message)
}
}