feat(logs): Phase 4 — zentrales Logsystem /api/v1/logs + /system/logs

Aggregierter Reader für alle EdgeGuard-Service-Journale + audit_log.

internal/services/syslogs/
  - 9 Quellen: edgeguard-api, edgeguard-scheduler, haproxy, squid,
    unbound, chrony, wg-quick@*, ulogd2, audit
  - journalctl --output=json + parser für __REALTIME_TIMESTAMP,
    PRIORITY (0-7 → debug/info/warn/error), MESSAGE, _HOSTNAME
  - audit-Reader nutzt bestehende audit.Repo.ListRecent
  - Concurrent fan-out über alle gewählten Quellen, dann merge-sort
    by Timestamp DESC + cap auf Limit (max 1000)
  - Client-Filter: Level, Grep (case-insensitive über message +
    actor + action + subject)

internal/handlers/logs.go:
  GET /api/v1/logs            — Filter via Query-Params
  GET /api/v1/logs/sources    — statische Quellen-Liste fürs UI

postinst: edgeguard → systemd-journal + adm Gruppen, damit
journalctl ohne sudo lesen kann. Verifiziert auf der Box: id zeigt
`groups=adm,systemd-journal,haproxy,edgeguard`.

UI: management-ui/src/pages/Logs — Multi-Source-Select, Level-Color-
Tags, Time-Range-Picker, Volltext-Suche, Auto-Refresh 5s (Toggle),
CSV-Export. Sidebar-Eintrag "Logs" unter System (FileSearchOutlined).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-12 21:29:38 +02:00
parent 66187e5b77
commit 827c364335
13 changed files with 774 additions and 5 deletions

View File

@@ -19,6 +19,7 @@
"firewall": "Firewall",
"firewallLive": "Firewall-Log",
"cluster": "Cluster",
"logs": "Logs",
"license": "Lizenz",
"settings": "Einstellungen",
"section": {
@@ -619,6 +620,31 @@
"cta": "Jetzt aktivieren →",
"openPage": "Lizenz-Seite öffnen →"
},
"logs": {
"title": "System-Logs",
"intro": "Aggregierter Blick auf alle Service-Journals + audit_log. Multi-Source-Auswahl, Level-Filter, Freitext-Suche, Zeit-Range, Auto-Refresh (5s).",
"autoOn": "Auto",
"autoOff": "Manuell",
"refresh": "Aktualisieren",
"refreshTooltip": "Einmalig neu laden",
"export": "CSV",
"exportTooltip": "Aktuelle Tabelle als CSV exportieren",
"exportEmpty": "Keine Einträge zum Exportieren",
"found": "{{n}} Einträge",
"limit": "Limit",
"empty": "Keine Einträge gefunden. Quellen-Auswahl ändern oder Zeit-Range erweitern.",
"col": {
"time": "Zeit",
"source": "Quelle",
"level": "Level",
"message": "Nachricht"
},
"filter": {
"sources": "Quellen wählen (alle wenn leer)",
"levels": "Level filtern",
"grep": "Volltext-Suche"
}
},
"fwlog": {
"title": "Firewall-Log (Live)",
"intro": "Pakete, die in nft-Regeln mit aktivem Log-Flag matchen, fließen via NFLOG → ulogd2 → JSONL hierher. WebSocket-Stream zeigt Live-Events; Ring-Buffer (1000) hält die letzten Treffer auch nach Reconnect.",