a5fd3aec90
Thread context.Context from callers instead of creating context.Background() at every call site. Engine stores its lifecycle ctx for use by triggerAlert goroutines. TUI Model carries ctx for store operations in Cmd closures. CLI commands create a root ctx and thread it through openStore, seed functions, and init methods. Only two intentional context.Background() remain in non-root positions: engine constructor default (overridden by Start) and drainWrites (parent already cancelled at shutdown).
93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
package monitor
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
)
|
|
|
|
const maxHistoryLen = 60
|
|
|
|
type SiteHistory struct {
|
|
Latencies []time.Duration
|
|
Statuses []bool
|
|
TotalChecks int
|
|
UpChecks int
|
|
}
|
|
|
|
func (e *Engine) InitHistory(ctx context.Context) {
|
|
all, err := e.db.LoadAllHistory(ctx, maxHistoryLen)
|
|
if err != nil {
|
|
e.AddLog("Failed to load check history: " + err.Error())
|
|
return
|
|
}
|
|
e.histMu.Lock()
|
|
defer e.histMu.Unlock()
|
|
for siteID, records := range all {
|
|
h := &SiteHistory{}
|
|
for _, r := range records {
|
|
h.TotalChecks++
|
|
if r.IsUp {
|
|
h.UpChecks++
|
|
}
|
|
h.Latencies = append(h.Latencies, time.Duration(r.LatencyNs))
|
|
h.Statuses = append(h.Statuses, r.IsUp)
|
|
}
|
|
e.histories[siteID] = h
|
|
}
|
|
if len(all) > 0 {
|
|
e.AddLog("Loaded check history from database")
|
|
}
|
|
}
|
|
|
|
func (e *Engine) recordCheck(siteID int, latency time.Duration, isUp bool) {
|
|
e.histMu.Lock()
|
|
defer e.histMu.Unlock()
|
|
|
|
h, ok := e.histories[siteID]
|
|
if !ok {
|
|
h = &SiteHistory{}
|
|
e.histories[siteID] = h
|
|
}
|
|
|
|
h.TotalChecks++
|
|
if isUp {
|
|
h.UpChecks++
|
|
}
|
|
|
|
h.Latencies = append(h.Latencies, latency)
|
|
if len(h.Latencies) > maxHistoryLen {
|
|
h.Latencies = h.Latencies[len(h.Latencies)-maxHistoryLen:]
|
|
}
|
|
|
|
h.Statuses = append(h.Statuses, isUp)
|
|
if len(h.Statuses) > maxHistoryLen {
|
|
h.Statuses = h.Statuses[len(h.Statuses)-maxHistoryLen:]
|
|
}
|
|
|
|
e.enqueueWrite(writeCheck{siteID: siteID, latencyNs: latency.Nanoseconds(), isUp: isUp})
|
|
}
|
|
|
|
func (e *Engine) GetHistory(siteID int) (SiteHistory, bool) {
|
|
e.histMu.RLock()
|
|
defer e.histMu.RUnlock()
|
|
h, ok := e.histories[siteID]
|
|
if !ok {
|
|
return SiteHistory{}, false
|
|
}
|
|
cp := SiteHistory{
|
|
TotalChecks: h.TotalChecks,
|
|
UpChecks: h.UpChecks,
|
|
Latencies: make([]time.Duration, len(h.Latencies)),
|
|
Statuses: make([]bool, len(h.Statuses)),
|
|
}
|
|
copy(cp.Latencies, h.Latencies)
|
|
copy(cp.Statuses, h.Statuses)
|
|
return cp, true
|
|
}
|
|
|
|
func (e *Engine) removeHistory(siteID int) {
|
|
e.histMu.Lock()
|
|
defer e.histMu.Unlock()
|
|
delete(e.histories, siteID)
|
|
}
|