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>
This commit is contained in:
Deploymentcenter Bot
2026-08-07 21:55:23 +02:00
co-authored by Claude Opus 5
parent a74c6fd990
commit 60e34b29f6
13 changed files with 2228 additions and 45 deletions
+121
View File
@@ -377,6 +377,74 @@ else:
---
## 8a. Fehler melden (Laufzeitfehler)
Für den globalen Exception-Handler einer Anwendung gibt es einen schlankeren
Eingang. Titel und Dringlichkeit leitet der Server ab:
```bash
curl -X POST https://dc.mhdf.de/api/errors/v1/report \
-H "Authorization: Bearer $DC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"project_slug": "polytrader",
"exception": "PDOException",
"message": "SQLSTATE[23000]: Duplicate entry '\''MKT-88213'\'' for key '\''uq_market'\''",
"stack_trace": "at Importer.php:142",
"level": "error",
"build": "v2.0.1",
"environment": "production",
"file": "src/Market/Importer.php",
"line": 142
}'
```
`level` unterscheidet die technische Art des Ereignisses — unabhängig von der
geschäftlichen Dringlichkeit:
| Wert | Bedeutung |
|---|---|
| `fatal` | Der Prozess hat sich beendet |
| `error` | Ein Vorgang ist fehlgeschlagen, das Programm läuft weiter (Vorgabe) |
| `warning` | Auffälligkeit ohne Funktionsverlust |
### Gruppierung
Gleiche Fehler werden zu einer Gruppe zusammengefasst und hochgezählt.
Veränderliche Bestandteile werden dabei ausgeblendet — Werte in
Anführungszeichen, die Ziffern enthalten, Speicheradressen, GUIDs, Zeitstempel
und Zeilennummern. Diese drei Meldungen ergeben **eine** Gruppe:
```
Duplicate entry 'MKT-88213' for key 'uq_market'
Duplicate entry 'AA-1' for key 'uq_market'
Duplicate entry 'X-99471' for key 'uq_market'
```
Ein anderer Unique-Key (`uq_orders`) bleibt dagegen eine eigene Gruppe — der
Schlüsselname enthält keine Ziffern und zählt damit zur Identität des Fehlers.
### Bekannte, harmlose Fehler
Manche Fehler treten betriebsbedingt auf und sind belanglos. Dafür gibt es
Ignore-Regeln, die im WebUI unter **Bugtracker → Ignore-Regeln** gepflegt
werden. Greift eine Regel, wird der Fehler weiterhin erfasst und **hochgezählt**,
bleibt aber aus der Übersicht heraus und löst keine Benachrichtigung aus:
```json
{ "status": "success", "item_id": 42, "ignored": true,
"ignore_rule_id": 3, "occurrence_count": 3841, "rate_alerted": false,
"message": "Als bekannt eingestuft, gezaehlt, nicht gemeldet." }
```
Der Zähler ist dabei der eigentliche Zweck: Zu jeder Regel lässt sich eine
Alarmschwelle hinterlegen. Dass ein bekannter Fehler auftritt, ist normal —
dass er plötzlich hundertmal so oft auftritt, ist ein Signal. Wird die Schwelle
überschritten, meldet die Antwort `"rate_alerted": true` und ein Webhook
`error.rate_exceeded` wird ausgelöst.
---
## 9. Watchdog-Heartbeat
Läuft dein Agent als Dienst, melde dich regelmäßig:
@@ -393,6 +461,59 @@ curl -X POST https://dc.mhdf.de/api/watchdog/v1/ping \
stuft der Evaluator den Monitor nach dem Doppelten auf `warning` und nach dem
Vierfachen auf `down`.
### Eigenen Gesundheitszustand mitsenden
Ein Heartbeat beweist nur, dass ein Thread läuft — nicht, dass die Anwendung
ihre Arbeit tut. Deshalb kann sie ihren Zustand selbst mitschicken:
```json
{ "source": "polytrader-worker",
"status": "warning",
"interval": 60,
"checks": {
"db": { "ok": true },
"market_feed": { "ok": false, "message": "Letzter Tick vor 14 min" },
"queue": { "ok": true, "value": 23 }
},
"metrics": { "cpu": 18, "ram": 42, "queue_depth": 23 } }
```
Das Deploymentcenter interpretiert die Namen der Prüfungen **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.
Der Weg ist bewusst ausgehend: Es müssen keine Ports auf den Zielmaschinen
geöffnet werden.
### Metriken
Numerische Werte aus `metrics` landen im Verlauf und lassen sich abfragen:
```bash
# Welche Metriken liefert dieser Monitor?
curl "https://dc.mhdf.de/api/watchdog/v1/metrics?source=polytrader-worker" \
-H "Authorization: Bearer $DC_TOKEN"
# Verlauf einer Metrik, auf 15-Minuten-Fenster verdichtet
curl "https://dc.mhdf.de/api/watchdog/v1/metrics?source=polytrader-worker&metric=queue_depth&hours=24" \
-H "Authorization: Bearer $DC_TOKEN"
```
Die Antwort enthält zusätzlich `deviation` — den Vergleich des aktuellen Werts
mit dem Durchschnitt der letzten sieben Tage desselben Monitors. Damit lassen
sich Auffälligkeiten erkennen, ohne für jedes Projekt Schwellwerte zu pflegen.
Verschachtelte Werte werden flach abgelegt: `{"cpu":{"load":1.2}}` wird zu
`cpu.load`. Rohwerte werden 14 Tage aufbewahrt.
### Abhängigkeiten
Ist bei einem Monitor `parent_source` gesetzt und fällt der übergeordnete
Monitor aus, werden Alarme für die Kinder unterdrückt. Ihr Zustand bleibt im
Dashboard sichtbar — es entsteht nur nicht für jede VM eines ausgefallenen
Hypervisors eine eigene Meldung.
---
## 10. Verfügbarkeit prüfen