4.4 KiB
Logging — Dateieingang Service
Stack
Entwicklung (Dev Services)
Quarkus startet den gesamten Observability-Stack automatisch über Dev Services.
Maven-Profil (pom.xml):
<profile>
<id>grafana</id>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-observability-devservices-lgtm</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
Mit ./mvnw quarkus:dev -Pgrafana startet automatisch:
- Loki — Log-Aggregation
- Grafana — Visualisierung / Dashboards (http://localhost:3000, admin/admin)
- Tempo — Distributed Tracing (optional nutzbar)
- Mimir — Metriken (optional nutzbar)
Laufzeit-Dependency (immer aktiv):
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-opentelemetry</artifactId>
</dependency>
Quarkus schickt Logs via OTLP direkt an den LGTM-Stack — kein Promtail, kein Log-File-Scraping.
Produktion
Einen OTLP-fähigen Collector vor dem produktiven Loki/Grafana-Stack betreiben:
- Grafana Alloy (Nachfolger von Promtail, OTLP-nativ)
- OpenTelemetry Collector
Quarkus-Konfiguration bleibt identisch — nur der OTLP-Endpoint-URL ändert sich.
Log-Hierarchie (MDC-Felder)
Ein ZIP-Verarbeitungslauf erzeugt Logs auf zwei Ebenen:
runId → ein ZIP-Verarbeitungslauf (gesetzt am Anfang jeder ZIP)
step → aktueller Pipeline-Step (gesetzt zu Beginn jedes Steps)
zipFilename wird zusätzlich als menschenlesbarer Kontext geloggt, ist aber kein MDC-Feld
(kein Filter-Kriterium, da runId eindeutiger ist).
MDC-Felder im Detail
| Feld | Typ | Beispielwert | Gesetzt in | Gelöscht in |
|---|---|---|---|---|
runId |
UUID | a1b2c3d4-... |
Beginn ZIP-Verarbeitung | finally nach ZIP |
step |
String | oci-upload |
Beginn jedes Pipeline-Steps | Ende jedes Steps |
MDC.clear() wird immer im finally-Block nach jeder ZIP aufgerufen —
kein Kontext sickert in die nächste ZIP.
Filtermöglichkeiten in Grafana (LogQL)
# Alle Logs eines Verarbeitungslaufs
{service="dateieingang"} | json | runId="a1b2c3d4"
# Alle Logs eines Pipeline-Steps über alle Läufe
{service="dateieingang"} | json | step="oci-upload"
# Nur Fehler
{service="dateieingang"} | json | level="ERROR"
# Fehler in einem bestimmten Lauf
{service="dateieingang"} | json | runId="a1b2c3d4" | level="ERROR"
Loki-Labels (wenige, statische Werte — keine hohe Kardinalität):
service=dateieinganglevel=INFO/WARN/ERRORenvironment=dev/prod
Alle anderen Felder (runId, step) werden per | json im Query-Body gefiltert, nicht als Label.
Log-Events pro Step
| Step | Level | Event / Inhalt |
|---|---|---|
api-trigger |
INFO | "Processing triggered by APEX, starting async pipeline" |
api-trigger |
WARN | "Pipeline already running, rejecting trigger (409)" |
sftp-list |
INFO | "N new ZIP files found on SFTP" |
sftp-list |
INFO | "No new ZIP files found on SFTP" |
sftp-download |
INFO | "ZIP <filename> downloaded (X bytes)" |
zip-extract |
INFO | "ZIP <filename> extracted: N files, M directories" |
zip-extract |
ERROR | "ZIP <filename> is corrupt or unreadable" |
oci-upload |
INFO | "Uploaded N files + marker to OCI in Xms" |
oci-upload |
WARN | "OCI upload attempt N/3 failed (503), retrying..." |
oci-upload |
ERROR | "OCI upload permanently failed (403) — check credentials" |
sftp-rename |
INFO | "SFTP rename: <file> → <file>.processed" |
sftp-rename |
INFO | "SFTP rename: <file> → <file>.error" |
ords-notify |
INFO | "ORDS endpoint called, HTTP 200" |
ords-notify |
WARN | "ORDS call failed (attempt N/3), retrying..." |
ords-notify |
WARN | "ORDS notification failed — marker is present, APEX will pick up next run" |
cleanup |
DEBUG | "Local files deleted: <path>" |
| Alle | ERROR | Fehler mit vollem MDC-Kontext, Exception-Message (nie Passwörter/Keys loggen) |
Fehlerverhalten (Logging-Perspektive)
- Fehler werden immer vor dem Rename zu
.errorgeloggt — damit der Log-Eintrag auch dann vorhanden ist, wenn das Rename selbst fehlschlägt - Der
runId-Kontext bleibt für den gesamten ZIP-Verarbeitungslauf erhalten — alle Logs einer ZIP sind in Grafana überrunIdfilterbar - Retry-Verhalten: siehe
Architecture.md— Abschnitt Fehlerbehandlung