Documentation
¶
Overview ¶
Package eventlog captures Mooring's own WARN/ERROR operational events — deploys, image builds, vulnerability scans, backups, git-fetch failures, scale decisions, self-heal actions — into a small, DEDUPED, file-backed store that the dashboard's Activity tab renders. It exists so an operator never has to `journalctl -u mooring | grep` to see what Mooring (or the things it manages) is doing or complaining about.
Bounded three ways so it can't grow without limit:
- DEDUP: identical repeats (same level+message+attrs) collapse to ONE row with a count + first/last-seen — so the "scale: refused" line every 10s is a single "×N, last …" row.
- TTL: rows whose last activity is older than the retention window (24h) are pruned.
- CAP: the number of DISTINCT rows is hard-capped (oldest evicted first).
It is persisted to a JSONL file (atomic rewrite), SEPARATE from the main SQLite DB (so it never contends with the single-conn database), and reloaded on start — so restarts don't lose recent activity and raw log volume never sits in memory. The events shown are exactly what already goes to journald, for the authenticated operator, so there is no new exposure; Mooring's WARN/ERROR logs are credential-free by design (see git.classifyErr, the audit log, etc.).
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Event ¶
type Event struct {
Level string `json:"level"` // WARN | ERROR
Msg string `json:"msg"` // the log message
Attrs string `json:"attrs,omitempty"` // stable "k=v k=v" (sorted) — the dedup discriminator + context
Count int `json:"count"` // how many times it has fired within the window
First int64 `json:"first"` // unix seconds, first occurrence
Last int64 `json:"last"` // unix seconds, most recent occurrence
}
Event is one deduped operational event.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler is a slog.Handler that TEES WARN+ERROR records into the Store (for the Activity tab) while passing EVERY record through to the wrapped base handler (journald) unchanged. A store hiccup never blocks or errors the log path — Record is O(1) amortized and lock-guarded.
func NewHandler ¶
NewHandler wraps base so WARN+ERROR records are also captured in store.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is a bounded, deduped, file-backed event store. Safe for concurrent use.
func New ¶
New opens (or creates) a store backed by path, loading any recent events already on disk.
func (*Store) Flush ¶
Flush prunes then writes the deduped set to disk IF it changed, via an atomic temp+rename. Cheap — the set is bounded. Call periodically and on shutdown.
func (*Store) Record ¶
Record adds/collapses one event. O(1) amortized: it never prunes here (that would put an O(n) scan on the logging hot path) — pruning is done lazily in List and by the periodic Flush. Eviction on a full store is the only O(n) branch and is rare (distinct rows stay small thanks to dedup).