logging architecture - smart-village-solutions/sva-studio GitHub Wiki
Dieses Dokument beschreibt die aktuelle Logging-Architektur im SVA Studio Monorepo, inklusive Datenfluss, Sicherheitsregeln, Konfigurationspunkten und Betriebsmodell.
Die Logging-Architektur verfolgt vier Kernziele:
- Einheitliche, strukturierte Logs ueber alle Server-Module.
- Korrelation von Logs mit Workspace- und Request-Kontext.
- Strikte PII-Kontrolle (Redaction + Label-Whitelist).
- Vendor-neutrale Pipeline ueber OpenTelemetry statt direkter Loki-Bindung im App-Code.
Abgedeckt sind:
- Server-seitiges App-Logging (
@sva/sdk/server). - Routing-Observability fuer
@sva/routinginklusive Guard-, Plugin- und Auth-Dispatch-Ereignissen. - OTEL-Export von Logs und Metriken (
@sva/monitoring-client/server). - OTEL Collector + Loki + Promtail im lokalen Monitoring-Stack.
- Tenant-/Request-Kontext per AsyncLocalStorage.
Nicht abgedeckt sind:
- produktives Browser-Logging außerhalb der lokalen Dev-Konsole.
- Alerting-Regeln im Detail (siehe Monitoring-Doku).
- Entry Point:
createSdkLogger(...) - Implementierung: Winston Logger mit
- JSON-Format fuer strukturierte Logs,
- Kontext-Anreicherung (
workspace_id,request_id,user_id,session_id), - Redaction sensibler Felder,
- modusspezifischen Transports fuer Console, Dev-UI und OTEL,
- direktem OTEL-Transport (
DirectOtelTransport), - Laufzeit-Rekonfiguration bereits erzeugter Logger nach erfolgreicher OTEL-Initialisierung.
Wichtig:
- Server-Code nutzt
@sva/sdk/server. - Keine direkten
console.*Calls im regulären Server-Code (Ausnahme: zirkulaere Abhaengigkeiten im Context-Middleware-Modul).
- AsyncLocalStorage speichert Request-/Workspace-Kontext.
- API:
runWithWorkspaceContextgetWorkspaceContextsetWorkspaceContext
- Extraktion via Request-Helper in
packages/sdk/src/middleware/request-context.server.ts.
Damit werden Logs in async Workflows automatisch mit Kontext angereichert.
-
initializeOtelSdk()startet OTEL idempotent. - Aktivierung:
- Production: verpflichtend aktiv
- Development: standardmäßig angefragt; per
ENABLE_OTEL=false|0explizit deaktivierbar
- Rueckgabewert: strukturiertes Ergebnisobjekt mit
status: ready|disabled|failed - Der Bootstrap erzwingt kein zusaetzliches OTEL-Diag-Console-Logging; regulaere App-Logs folgen ausschliesslich dem Runtime-Modell.
-
flushOtelSdk()fuer kontrolliertes Flush-Verhalten beim Shutdown.
- Nur in der Entwicklungsumgebung gerendert.
- Zeigt Browser-Logs und redaktierte Server-Logs in einer lokalen Debug-Konsole am Seitenende.
- Browser-Logs werden clientseitig gesammelt.
- Server-Logs werden ueber einen redaktierten In-Memory-Buffer im SDK und Polling aus der App bereitgestellt.
- Der zugehoerige Serverpfad liefert ausserhalb von Development keine Eintraege aus.
- Start via
startOtelSdk(...). - Enthält:
- OTLP Log Exporter (
/v1/logs) - OTLP Metric Exporter (
/v1/metrics) -
RedactingLogProcessorals zentrale Label/PII-Policy im OTEL-Layer - Batch-Verhalten mit dev/prod-optimierten Flush-Intervallen.
- OTLP Log Exporter (
- Stellt globalen Zugriff auf den OTEL LoggerProvider bereit.
-
DirectOtelTransportverwendet diesen Provider fuer direkte Log-Emission.
- OTEL Collector:
- Receives OTLP gRPC + HTTP
- Exportiert Logs nach Loki, Metriken nach Prometheus
- Loki:
- Log Storage + Query
- Promtail:
- Fallback fuer Container-stdout/stderr, plus zusätzliche Label-Filterung.
App Code (createSdkLogger)
-> Winston Logger (JSON + Kontext + Redaction)
-> Console Transport (Development)
-> Development UI Transport (Development)
-> DirectOtelTransport (nur wenn OTEL ready)
-> Global OTEL LoggerProvider
-> OTEL SDK LogRecord
-> RedactingLogProcessor (Label-Whitelist + PII-Regeln)
-> OTLP Export (/v1/logs)
-> OTEL Collector
-> Loki
-> Grafana / LogQL
Fallback-Pfad:
Container stdout/stderr
-> Promtail (docker stage + relabel)
-> Loki
-
component: Herkunft des Logs (z. B.auth,bootstrap). -
environment:development|test|production. -
workspace_id: Mandantenkontext, wenn vorhanden.
Der Logger injiziert Kontextdaten in context:
request_iduser_idsession_id
Diese werden als Kontext-Payload gefuehrt, nicht als frei skalierende Labels. Pseudonyme technische IDs bleiben dennoch personenbeziehbar und duerfen nur bei begruendeter Betriebsnotwendigkeit erscheinen.
DirectOtelTransport mappt Winston-Level auf OTEL Severity:
-
error-> 17 -
warn-> 13 -
info-> 9 -
debug-> 5 -
verbose-> 1
@sva/routing nutzt fuer routing-relevante Entscheidungen einen kleinen Diagnostics-Vertrag statt verteilter Logger-Zugriffe.
- Client- und Server-Route-Factories verdrahten standardmaessig einen Routing-Diagnostics-Adapter; ein expliziter
RoutingDiagnosticsHookkann diesen Default ueberschreiben. - Die Event-zu-Logger-Zuordnung erfolgt zentral ueber
createRoutingDiagnosticsLogger(...). - Serverseitig binden Auth-Routen und allgemeine Routing-Factories denselben Adapter an
createSdkLogger(...)und damit an den OTEL-Pfad. - Standardmaessig geloggt werden Guard-Denials, Plugin-Guard-Anomalien, Handler-Dispatch, Handler-Completion, unbehandelte Handler-Fehler und
405 Method Not Allowed.
eventroutereasonpluginredirect_targetrequired_rolesunsupported_guardmethodallowstatus_codeduration_msworkspace_idrequest_idtrace_iderror_typeerror_message
Nicht zulaessig sind insbesondere aufgeloeste Pfade mit IDs, rohe Query-Strings, Token-URLs, session_id, email, ip_address, user_agent und Stack-Traces.
Die Policy ist mehrstufig implementiert.
In createSdkLogger:
- sensitive keys werden auf
[REDACTED]gesetzt (z. B.password,token,authorization,api_key,secret,email) - E-Mails werden maskiert (Pattern-basiert).
- sensitive Query-Parameter in URLs wie
id_token_hint,access_token,refresh_tokenundcodewerden maskiert - JWT-aehnliche Strings und Inline-Bearer-Tokens in Freitexten werden heuristisch auf
[REDACTED_JWT]bzw.[REDACTED]reduziert - tokenhaltige Redirect- oder Logout-URLs duerfen fachlich gar nicht erst als Rohwert den Logger erreichen; zulaessig ist nur eine sichere Summary ohne Query-Geheimnisse
In RedactingLogProcessor:
-
workspace_idwird aus AsyncLocalStorage injiziert. - Nur erlaubte Label bleiben erhalten (Whitelist):
workspace_idcomponentenvironmentlevel
- Verbotene/high-cardinality/PII Label werden verworfen.
- Kontextdaten werden in den Body serialisiert.
In dev/monitoring/promtail/promtail-config.yml:
-
labeldropentfernt verbotene Labels. -
labelkeeperzwingt erlaubten Labelsatz fuer Fallback-Logs.
- Console-Logging ist immer aktiv.
- Die lokale Dev-Konsole im Frontend ist immer aktiv.
- OTEL wird standardmäßig initialisiert, aber nur bei erfolgreichem SDK-Start als aktiver Transport zugeschaltet.
- OTEL kann fuer lokale Entwicklungslaeufe explizit via
ENABLE_OTEL=false|0deaktiviert werden. - Lokale Diagnosekanaele folgen denselben Redaction-Regeln wie OTEL; Development ist kein Privacy-Sonderfall.
- Console-Logging ist aus.
- Die Dev-Konsole ist aus.
- OTEL ist verpflichtend aktiv.
- Strukturiertes Logging und Export ueber Collector verpflichtend.
- Graceful Shutdown mit
forceFlush+sdk.shutdown().
NODE_ENVENABLE_OTELOTEL_SERVICE_NAMEOTEL_EXPORTER_OTLP_ENDPOINT
- OTEL Collector:
4317(gRPC),4318(HTTP),13133(health) - Loki:
3100 - Promtail:
3101 - Prometheus:
9090 - Grafana:
3001
- Logger via
createSdkLogger({ component: '...' })erstellen. - Request-Handler mit
withRequestContext(...)kapseln. - Strukturierte Meta-Felder statt freiem String-Ballast nutzen.
- Keine PII in Labels schreiben.
- Keine tokenhaltigen URLs loggen; stattdessen sichere Summary-Felder verwenden.
- Bei neuen Services
componentstabil benennen (dash-case oder snake_case, konsistent).
- Kein
console.logals App-Logging-Ersatz. - Kein direkter Loki-Client im Feature-Code.
- Keine hochkardinalen IDs als Labels.
- Keine Secrets/Tokens in Log-Meta.
- Keine Redirect- oder Logout-URLs mit sensitiven Query-Parametern im operativen Logging.
- SDK/Monitoring-Tests unter:
packages/sdk/tests/packages/monitoring-client/tests/-
packages/auth-runtime/src/session.test.ts(session-bezogen)
- Monitoring-Stack starten (
docker-compose.monitoring.yml). - App starten und Flows triggern.
- Optional OTEL lokal deaktivieren (
ENABLE_OTEL=false), wenn nur Console + Dev-Konsole genutzt werden sollen. - In Grafana/Loki verifizieren:
- Labels entsprechen Whitelist.
- PII ist maskiert/redacted.
-
workspace_idist vorhanden (wo Kontext vorhanden ist).
- Doppelte Pipeline (OTEL + Promtail) kann ohne saubere Trennung Duplikate erzeugen.
- Context-Middleware nutzt in einem Sonderfall
console.warn(zirkulaere Abhaengigkeit zum Logger), bewusst begrenzt auf Development-Warnpfad. - In Development kann die Anwendung bewusst ohne aktiven OTEL-Transport laufen; Console und Dev-Konsole bleiben dann die primären Diagnosekanaele.
packages/sdk/src/logger/index.server.tspackages/sdk/src/middleware/request-context.server.tspackages/sdk/src/observability/context.server.tspackages/sdk/src/server/bootstrap.server.tspackages/monitoring-client/src/otel.server.tspackages/monitoring-client/src/logger-provider.server.tsdev/monitoring/otel-collector/otel-collector.ymldev/monitoring/promtail/promtail-config.ymldocker-compose.monitoring.ymldocs/development/observability-best-practices.mddocs/development/monitoring-stack.mddocs/adr/README.md