Skip to content

fix(logs/plugins): Plugin-Version zum Zeitpunkt des Eintrags, kein WARN beim absichtlichen Stopp - #389

Merged
CallMeTechie merged 3 commits into
masterfrom
fix/log-plugin-version-and-shutdown-warn
Nov 2, 2026
Merged

CallMeTechie merged 3 commits into
masterfrom
fix/log-plugin-version-and-shutdown-warn

Conversation

@CallMeTechie

@CallMeTechie CallMeTechie commented Nov 2, 2026 •

Copy link
Copy Markdown
Owner

Zwei kleine Fehler, die in einem Export von Logs & Monitoring aufgefallen sind.

1. Plugin-Log-Einträge mit falscher Version (fix(logs))

logEvents.fromPlugin nahm für Einträge aus plugin_logs die aktuell installierte Version (Kontext „Name Version“, fields.version). Ein Eintrag vom 01.11. stand so als „Mail 1.7.1“ da, obwohl damals 1.7.0 lief.

  • Migration 122: ALTER TABLE plugin_logs ADD COLUMN plugin_version TEXT – eine Zeile, keine Datenumwandlung. Es gibt genau einen Schreibpfad (registry.addLog), deshalb war die Spalte die kleine und richtige Lösung statt die Version wegzulassen.
  • registry.addLog(id, level, message, version): Der Plugin-Prozess (runtime.log) übergibt seine eigene Version – während eines Updates hält die Registry schon die nächste, der alte Prozess schreibt aber noch. Andere Aufrufer (Host-Meldungen wie „enabled by an administrator“) bekommen per COALESCE(?, (SELECT version FROM plugins …)) die installierte Version zum Schreibzeitpunkt.
  • logEvents: Kontext, fields.version und raw.version kommen aus der gespeicherten Spalte. Alte Zeilen (NULL) zeigen keine Version, nicht die aktuelle. Liste, Detail, Probleme und Export (CSV/JSON/NDJSON/Text, Fehlerbericht) nutzen dasselbe Eintragsobjekt. versions.json im Fehlerbericht und die Plugin-Liste im Filter zeigen weiterhin bewusst die installierten Versionen.

2. WARN beim normalen Neustart (fix(plugins))

Beim Update/Neustart des Hosts erschien je Plugin mit Hintergrundlauf background run failed: plugin process ended als Warnung: stop() beendet den Prozess, onExit bricht offene Aufrufe ab, runTick loggte das als warn.

  • runtime: Aufrufe, die enden, weil der Host den Prozess absichtlich beendet (wanted = false durch stop() – Herunterfahren, Update, Plugin-Update, Deaktivieren, Deinstallieren, Lizenz-Stopp, Neustart durch einen Administrator), tragen stopped: true (Code bleibt ERR_NOT_RUNNING bzw. ERR_TIMEOUT). Das gilt auch für „plugin did not answer in time“, wenn der Timeout während des Stopps abläuft.
  • runTick und groups.onChange (groupsChanged failed) loggen solche Fehler als debug. Stirbt der Prozess unerwartet (Absturz, Ping-Timeout → SIGKILL), bleibt es eine Warnung samt „process ended … restart in“.
  • Andere ähnliche Stellen geprüft: publicLinkEvent loggt schon debug, Start-Timeout und Ping-Prüfung laufen im Zustand stopping nicht, alle übrigen Aufrufer schlucken Fehler oder geben sie an die HTTP-Anfrage zurück.

3. Reihenfolge auf stdout bei logger.fatal + exit (fix(logs), aus der CI)

test (Node 22) scheiterte an tests/server_log.test.js („writes both, keeps secrets out, flushes a fatal line before exit“): auf stdout stand bye vor hello. Ursache ist echt, kein Zufall: Mit eingeschalteter Log-Datei schreibt der Logger stdout über ein asynchrones pino.destination(). Beim process.exit nach fatal war hello noch im Thread-Pool unterwegs, während pino den Rest synchron schrieb. Unter CPU-Last lokal in 33 von 40 Läufen reproduziert, mit dem Fix 0 von 40.

  • src/utils/logger.js: stdout als synchrones Ziel (sync: true) im Zweig mit Log-Datei; ohne Datei (GC_SERVER_LOG=off) unverändert.
  • Neuer Test: derselbe Ablauf zehnmal, Reihenfolge one, two, three auf stdout.

Tests

  • tests/logs_hub.test.js: addLog speichert die übergebene bzw. die installierte Version; Liste, Detail und NDJSON-Export zeigen „Mail 1.7.0“ bzw. ohne Version, nie die installierte 1.7.1.
  • tests/plugins_lifecycle.test.js: laufender Hintergrundlauf + Deaktivieren, Neustart durch Admin und stopAll() (Herunterfahren) → genau ein debug-Eintrag; Timeout während des Stopps → stopped: true, normaler Timeout ohne; Absturz während eines Laufs → weiterhin warn; Plugin-Logs tragen die Version des Prozesses.
  • tests/server_log.test.js: Reihenfolge auf stdout vor einem Fatal-Exit (zehn Läufe).
  • Vorher rot (ohne die Änderungen in src/; der Logger-Test unter Last), nachher grün. ESLint (security, no-undef) und die i18n-/Template-Checks sauber.

https://claude.ai/code/session_016xX1efcZF1f6G9rhmaJNLD


Generated by Claude Code

Claude added 3 commits November 2, 2026 10:54
…n hat

Logs & Monitoring nahm für Einträge aus plugin_logs die aktuell
installierte Plugin-Version (Kontext „Name Version“ und fields.version) –
ein Eintrag vom 01.11. stand als „Mail 1.7.1“ da, obwohl damals 1.7.0 lief.

- Migration 122: plugin_logs.plugin_version (TEXT, NULL für alte Zeilen)
- registry.addLog(id, level, message, version): der Plugin-Prozess trägt
  seine eigene Version ein (während eines Updates hält die Registry schon
  die nächste), Meldungen des Hosts die installierte
- logEvents: Kontext, fields.version und raw aus der gespeicherten Version;
  alte Einträge ohne Version zeigen keine (nicht die aktuelle). Liste,
  Detail, Probleme und Export nutzen denselben Eintrag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xX1efcZF1f6G9rhmaJNLD
…endet

Beim Neustart oder Update des Hosts stand für jedes Plugin mit
Hintergrundlauf „background run failed: plugin process ended“ als Warnung
im Log: stop() beendet den Prozess, offene Aufrufe werden abgebrochen.

- runtime: Aufrufe, die durch stop() enden (Herunterfahren, Update,
  Plugin-Update, Deaktivieren, Deinstallieren, Neustart durch einen
  Administrator), tragen stopped: true – auch „plugin did not answer in
  time“, wenn der Timeout während des Stopps abläuft
- runTick und groupsChanged loggen solche Fehler als debug; stirbt der
  Prozess unerwartet (Absturz, Ping-Timeout), bleibt es eine Warnung

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xX1efcZF1f6G9rhmaJNLD
… steht

Mit eingeschalteter Server-Log-Datei schrieb der Logger stdout über ein
asynchrones pino.destination(). Beendete sich der Prozess nach
logger.fatal, war eine frühere Zeile oft noch unterwegs, während pino den
Rest beim exit synchron schrieb – auf stdout stand die Fatal-Meldung dann
vor den Zeilen davor. Unter Last passierte das etwa bei jedem zweiten Lauf
(CI: tests/server_log.test.js „writes both, keeps secrets out, flushes a
fatal line before exit“, Node 22).

stdout ist jetzt ein synchrones Ziel (sync: true). Der Pfad ohne
Log-Datei (GC_SERVER_LOG=off) bleibt unverändert. Neuer Test führt den
Ablauf zehnmal aus und prüft die Reihenfolge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xX1efcZF1f6G9rhmaJNLD
@CallMeTechie
CallMeTechie merged commit 5d3e9e7 into master Nov 2, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants