Files
Deploymentcenter/sql/migrations/007_error_stream_and_metrics.sql
T
Deploymentcenter BotandClaude Opus 5 60e34b29f6 feat(errors, watchdog): Fehler-Stream mit Ignore-Regeln, Metrik-Verlauf, Abhängigkeits-Alarme
Fehler-Schnittstelle
- Neuer schlanker Eingang POST /api/errors/v1/report für den globalen
  Exception-Handler einer Anwendung. Titel und Dringlichkeit leitet der Server
  ab; gespeichert wird in derselben Tabelle wie der Bugtracker. Ein zweiter
  Speicher wäre nur ein zweiter Ort, an dem man suchen müsste.
- error_level (fatal/error/warning) trennt die technische Art des Ereignisses
  von der geschäftlichen Dringlichkeit. Ein Duplicate-Entry ist technisch ein
  error, geschäftlich belanglos — beides zu vermischen war der Grund, warum
  solche Meldungen als Bug im Dashboard landeten.

Ignore-Regeln gegen bekanntes Rauschen
- bugtracker_ignore_rules mit contains/regex/exception_class, Pflichtfeld für
  die Begründung und optionaler Alarmschwelle.
- Ein Treffer bedeutet nicht "wegwerfen": Der Fehler wird weiterhin erfasst und
  hochgezählt, bleibt aber aus der Übersicht heraus und löst keine
  Benachrichtigung aus. Der Zähler ist der eigentliche Zweck — dass ein
  bekannter Fehler auftritt, ist normal; dass er plötzlich hundertmal so oft
  auftritt, ist ein Signal. Dafür das rollende Stundenfenster und
  error.rate_exceeded.
- Neue Regeln lassen sich rückwirkend auf bestehende Einträge anwenden.

Gruppierung überarbeitet
- Der Schlüssel nahm bisher 300 Zeichen Stacktrace auf. Derselbe Fehler
  zersplitterte dadurch, sobald ein Aufrufer den Stack einmal mitschickte und
  einmal nicht. Jetzt zählt der Ursprungsort: bevorzugt die Dateiangabe, sonst
  der erste Rahmen des Stacktrace.
- Die Normalisierung ersetzte nur Zahlen ab vier Stellen, wodurch
  'AA-1' und 'BB-2' getrennt blieben. Werte in Anführungszeichen, die Ziffern
  enthalten, gelten jetzt als veränderlich — der Schlüsselname bleibt erhalten,
  sodass verschiedene Unique-Keys unterscheidbar sind. Mit 9 Testfällen belegt.

Metrik-Verlauf
- watchdog_metrics speichert numerische Heartbeat-Werte mit Zeitstempel.
  Zuvor wurde metrics_json bei jedem Heartbeat überschrieben; damit ließ sich
  "die Platte läuft seit drei Tagen voll" nicht erkennen, nur "sie ist voll".
- GET /api/watchdog/v1/metrics liefert den verdichteten Verlauf und die
  Abweichung vom eigenen Sieben-Tage-Durchschnitt. Dieser relative Ansatz
  braucht keine projektspezifischen Schwellwerte.
- Aufbewahrung 14 Tage, Bereinigung stündlich durch den Evaluator.

Health-Checks per Push statt Abruf
- Der Heartbeat nimmt ein checks-Objekt entgegen, das die Anwendung selbst
  ermittelt. Das Deploymentcenter interpretiert die Namen nicht, es liest nur
  ok und message — was "gesund" bedeutet, entscheidet jede Anwendung selbst.
  Schlägt eine Prüfung fehl, wird ein als ok gemeldeter Heartbeat auf warning
  herabgestuft.
- Bewusst ausgehend: auf den Zielmaschinen müssen keine Ports geöffnet werden.

Abhängigkeitsbewusste Alarmierung
- Fällt ein Monitor aus, dessen Parent selbst unten ist, wird der Alarm
  unterdrückt. Der Zustand bleibt sichtbar. Vorher erzeugte ein ausgefallener
  Hypervisor mit zwölf VMs dreizehn Meldungen für ein Problem.
- Mehrere Ebenen und fehlerhafte Hierarchien (Zyklen, gelöschte Parents) sind
  abgesichert; mit 10 Testfällen belegt.

WebUI
- Neue Ansicht "Fehler-Stream" mit Filtern nach Projekt, Fehlerklasse,
  Umgebung, Zeitraum und Sichtbarkeit sowie Volltextsuche und Pagination.
  Stummgeschaltete Einträge sind standardmäßig ausgeblendet.
- Verwaltung der Ignore-Regeln inklusive Trefferzähler.
- Die Detailansicht zeigt Fehlerklasse, Stummschaltungsgrund und die Häufung
  im laufenden Stundenfenster.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 21:55:23 +02:00

102 lines
5.4 KiB
SQL

-- Migration 007: Fehler-Stream, Ignore-Regeln, Metrik-Verlauf, Health-Checks
--
-- Additive Migration. Der Migrator toleriert 1050/1060/1061/1062.
-- ---------------------------------------------------------------------------
-- 1. Fehlerklasse getrennt vom Schweregrad
-- ---------------------------------------------------------------------------
-- severity beschreibt die geschaeftliche Dringlichkeit (low ... critical),
-- error_level die technische Art des Ereignisses. Ein "Duplicate entry" ist
-- technisch ein error, geschaeftlich aber belanglos - beides zu vermischen
-- war der Grund, warum solche Meldungen bisher als Bug im Dashboard landeten.
ALTER TABLE bugtracker_items
ADD COLUMN error_level ENUM('fatal','error','warning') NULL AFTER severity;
-- Status "ignored": bekannt, harmlos, wird weiter gezaehlt, aber nicht gemeldet.
ALTER TABLE bugtracker_items
MODIFY COLUMN status ENUM('open','planned','in_progress','resolved','closed','rejected','ignored')
NOT NULL DEFAULT 'open';
-- Rollendes Stundenfenster fuer die Ratenerkennung. Interessant ist nicht,
-- DASS ein bekannter Fehler auftritt, sondern wenn er ploetzlich viel
-- haeufiger auftritt.
ALTER TABLE bugtracker_items ADD COLUMN rate_window_start DATETIME NULL AFTER occurrence_count;
ALTER TABLE bugtracker_items ADD COLUMN rate_window_count INT NOT NULL DEFAULT 0 AFTER rate_window_start;
ALTER TABLE bugtracker_items ADD COLUMN rate_alerted_at DATETIME NULL AFTER rate_window_count;
-- Welche Regel hat dieses Item stummgeschaltet?
ALTER TABLE bugtracker_items ADD COLUMN ignore_rule_id INT NULL AFTER error_level;
ALTER TABLE bugtracker_items ADD KEY ix_bt_error_level (error_level, last_seen_at);
-- ---------------------------------------------------------------------------
-- 2. Ignore-Regeln
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS bugtracker_ignore_rules (
id INT AUTO_INCREMENT PRIMARY KEY,
project_slug VARCHAR(64) NULL, -- NULL = gilt fuer alle Projekte
match_type ENUM('contains','regex','exception_class') NOT NULL DEFAULT 'contains',
pattern VARCHAR(255) NOT NULL,
-- Warum ist das harmlos? Pflichtfeld, damit in sechs Monaten noch
-- nachvollziehbar ist, weshalb hier weggeschaut wird.
reason TEXT NOT NULL,
-- Ab wie vielen Vorkommnissen pro Stunde soll trotzdem alarmiert werden?
-- NULL = nie alarmieren.
alert_on_rate INT NULL,
enabled TINYINT(1) NOT NULL DEFAULT 1,
match_count BIGINT NOT NULL DEFAULT 0,
last_match_at DATETIME NULL,
created_by VARCHAR(100) NOT NULL DEFAULT 'admin',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY ix_ignore_project (project_slug, enabled)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------------------
-- 3. Metrik-Verlauf
-- ---------------------------------------------------------------------------
-- Bisher wurde metrics_json bei jedem Heartbeat ueberschrieben - es gab immer
-- nur den letzten Moment. Damit laesst sich "Platte laeuft seit drei Tagen
-- voll" nicht erkennen, sondern nur "Platte ist voll".
CREATE TABLE IF NOT EXISTS watchdog_metrics (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
source VARCHAR(100) NOT NULL,
instance VARCHAR(100) NOT NULL DEFAULT 'default',
metric_key VARCHAR(64) NOT NULL,
metric_value DOUBLE NOT NULL,
recorded_utc DATETIME NOT NULL,
KEY ix_metric_lookup (source, instance, metric_key, recorded_utc),
KEY ix_metric_time (recorded_utc)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ---------------------------------------------------------------------------
-- 4. Health-Checks per Push
-- ---------------------------------------------------------------------------
-- Die Anwendung sendet ihren Gesundheitszustand im Heartbeat mit. Das
-- Deploymentcenter interpretiert die Namen der Pruefungen nicht - es liest
-- nur ok und message. Damit muessen auf den Zielmaschinen keine Ports
-- geoeffnet werden.
ALTER TABLE watchdog_monitors ADD COLUMN health_json JSON NULL AFTER metrics_json;
ALTER TABLE watchdog_monitors ADD COLUMN failing_checks VARCHAR(255) NULL AFTER health_json;
-- Alarme fuer Kinder unterdruecken, solange der Parent unten ist.
ALTER TABLE watchdog_monitors ADD COLUMN alert_suppressed_by VARCHAR(100) NULL AFTER failing_checks;
-- Aufraeumauftrag fuer den Metrik-Verlauf
INSERT INTO watchdog_cron_jobs (name, interval_sec, enabled) VALUES
('metrics_cleanup', 86400, 1)
ON DUPLICATE KEY UPDATE interval_sec = VALUES(interval_sec);
-- ---------------------------------------------------------------------------
-- 5. Beispielregel, damit der Aufbau sofort erkennbar ist
-- ---------------------------------------------------------------------------
-- Bewusst deaktiviert (enabled = 0): sie dient als Vorlage und greift erst,
-- wenn sie im WebUI bewusst eingeschaltet wird.
INSERT INTO bugtracker_ignore_rules
(project_slug, match_type, pattern, reason, alert_on_rate, enabled, created_by)
SELECT 'polytrader', 'contains', 'Duplicate entry',
'Marktdaten kommen doppelt aus dem Feed. Der Eintrag wird ohnehin nur einmal benoetigt, die Verarbeitung laeuft normal weiter. Alarm erst bei auffaelliger Haeufung.',
500, 0, 'system:vorlage'
WHERE NOT EXISTS (
SELECT 1 FROM bugtracker_ignore_rules WHERE project_slug = 'polytrader' AND pattern = 'Duplicate entry'
);