Observability
Kurzantwort: Metriken, Health-Indikatoren und Tracing sind optional: Die
Module sprechen gegen eine Abstraktion und aktivieren Micrometer nur, wenn die
Anwendung eine MeterRegistry mitbringt. Ohne sie laufen No-Op-Implementierungen
ohne Kosten. Sensible Werte – rohe Mandantenkennungen, Pfade, Tokens – tauchen
weder in Logs noch in Metrik-Tags auf.
Aktivierungsmodell
Abschnitt betitelt „Aktivierungsmodell“flowchart TB
A["Anwendung startet"] --> B{"MeterRegistry-Bean vorhanden?<br/>(Micrometer/Actuator eingebunden)"}
B -->|nein| N["NoOp-Implementierung<br/>keine Metriken, keine Kosten"]
B -->|ja| M["Micrometer-Implementierung"]
M --> C{"Actuator im Classpath?"}
C -->|ja| H["zusätzlich Health-Indikator"]
micrometer-core und spring-boot-actuator sind in den Modulen als optional
deklariert – nicht transitiv. Die Anwendung entscheidet.
Metriken der Persistenz
Abschnitt betitelt „Metriken der Persistenz“Präfix cdms.persistence:
| Metrik | Typ | Tags | Bedeutung |
|---|---|---|---|
cdms.persistence.routing | Counter | target=system|tenant | Routing-Entscheidungen |
cdms.persistence.routing.failures | Counter | reason=<CDMS_*-Code> | fehlgeschlagene Auflösungen |
cdms.persistence.tenant_database.created | Counter | – | provisionierte Mandantendatenbanken |
cdms.persistence.tenant_catalog.cache | Counter | result=hit|miss | Wirksamkeit des Katalog-Caches |
cdms.persistence.factory_cache.size | Gauge | – | Cache-Belegung |
cdms.persistence.factory_cache.evictions | Counter | – | geräumte Factories |
cdms.persistence.entity_manager_factory.creation | Timer | – | Dauer der Factory-Erzeugung |
cdms.persistence.tenant_catalog.load | Timer | – | Dauer des Katalogzugriffs |
Der Routing-Counter zählt Auflösungen, nicht Requests – ein Request kann mehrere auslösen.
Metriken der Dateiablage
Abschnitt betitelt „Metriken der Dateiablage“| Metrik | Typ | Tags | Bedeutung |
|---|---|---|---|
cdms.files.operation | Counter | operation, result | Storage-Operationen nach Ausgang |
cdms.files.operation.duration | Timer | operation | Dauer |
cdms.files.bytes | Counter | direction | bewegte Bytes |
operation ist save, read, delete, listVersions, readVersion oder
rollback.
Weder Mandant noch Modell sind Tags. Der Mandant ist unbegrenzt und identifizierend – ein Metrik-Backend behält jede jemals gesehene Zeitreihe, ein Mandanten-Tag machte aus einer Metrik eine wachsende Kundenliste. Speichervolumen pro Mandant ist eine Reporting-Frage und wird aus den Metadaten beantwortet. Ein Test läuft über alle registrierten Meter und schlägt bei jedem fremden Tag fehl.
Metriken abschalten
Abschnitt betitelt „Metriken abschalten“Kein modulspezifischer Schalter – der Standardweg von Spring Boot genügt:
# alle Metriken des Persistenzmoduls ausmanagement.metrics.enable.cdms.persistence=false# nur den Routing-Counter ausmanagement.metrics.enable.cdms.persistence.routing=falseHealth-Indikatoren
Abschnitt betitelt „Health-Indikatoren“| Indikator | prüft |
|---|---|
PersistenceHealthIndicator | Erreichbarkeit der Persistenzziele |
FileStorageHealthIndicator | Erreichbarkeit und Beschreibbarkeit des basePath |
CacheHealthIndicator | Cache-Zustand |
Beim Start prüft FileStorageStartupCheck das Storage-Wurzelverzeichnis – eine
fehlende oder nicht beschreibbare Ablage fällt beim Start auf, nicht beim ersten
Upload.
Endpunkte: :8081/actuator/health, …/health/liveness.
Logging
Abschnitt betitelt „Logging“| Was | Verhalten |
|---|---|
| Routing | über cdms.database.log-routing (Standard false); protokolliert Zieltyp und gehashte Mandantenkennung, nie die rohe |
| Fehler | immer auf warn, mit CDMS_*-Code |
| Provisionierung | auf info |
| Storage | parametrisiert (model={} fileId={}), Ausnahme als Ursache angehängt |
Nicht geloggt werden: Passwörter, Tokens, vollständige JDBC-URLs, Request-Payloads, rohe Mandantenkennungen, absolute Pfade in der Nachricht, Dateinamen fremder Datensätze, Dateiinhalte.
Ein Detail mit Absicht: Die Meldung einer IOException enthält den absoluten
Pfad. Sie landet deshalb im Stacktrace (den ein Operator beim Untersuchen liest)
und nicht im Nachrichtenfeld (das indiziert, aggregiert und aufbewahrt wird).
Tracing
Abschnitt betitelt „Tracing“Umgesetzt über die Micrometer Observation API: Die zeitgemessenen
Operationen laufen durch eine Observation – ist ein Tracer vorhanden,
liefert dieselbe Instrumentierung zusätzlich Spans.
Die generierten APIs sind mit @Observed annotiert
(z. B. @Observed(name = "CustomerApi.create.json")), sodass Endpunkte einzeln
messbar sind.
Was noch fehlt
Abschnitt betitelt „Was noch fehlt“- eine durchgehende Korrelations-/Request-ID über alle Schichten (der
RequestContextträgt einerequestId, die Storage-Logs nutzen sie noch nicht) - Zähler für den Ausgang der Transaktionsklammer (Commits/Rollbacks)