Observability
Zielgruppe: DevOps. Seit Phase 7 mit echten Daten - vorher lieferte
infra/prometheus/prometheus.ymlnur "down"-Targets, weil keine Metriken exponiert wurden (siehecommon-observability).
Die drei Saeulen und ihre Werkzeuge in diesem Projekt
| Saeule | Beantwortet | Werkzeug hier |
|---|---|---|
| Metriken | "Wie viele Requests/Sekunde, wie hoch ist die Fehlerrate, wie voll ist der Heap?" | Micrometer → Prometheus → Grafana |
| Distributed Tracing | "Dieser eine Request war langsam - in WELCHEM der sechs beteiligten Services genau?" | Micrometer Tracing (Brave) → Zipkin |
| Logs | "Was genau ist passiert, mit welchen Werten?" | strukturierte Log-Zeilen mit Correlation-Id (siehe CorrelationIdFilter, common-web), als JSON via logstash-logback-encoder → Promtail → Grafana Loki |
Wie ein Service Metriken/Traces bekommt: common-observability
Ein Service muss dafuer NICHTS programmieren - common-observability (siehe
Pattern-Katalog) ist ein reines Abhaengigkeits-Modul:
micrometer-registry-prometheus (exponiert /actuator/prometheus) und
micrometer-tracing-bridge-brave + zipkin-reporter-brave (sendet Spans an Zipkin). Sobald
diese Bibliotheken auf dem Klassenpfad liegen, konfiguriert Spring Boot beides automatisch -
"Classpath-getriebene Auto-Configuration", siehe die Modul-Beschreibung in
common-observability/pom.xml.
Was WEITERHIN pro Service konfiguriert werden muss, ist bewusst zentral im Config Server gelöst
(config-server/src/main/resources/config-repo/application.yml):
management.endpoints.web.exposure.include: health,info,prometheus(Actuator-Endpunkte sind standardmaessig NICHT alle ueber HTTP erreichbar - explizite Freischaltung noetig)management.tracing.sampling.probability: 1.0(100% Sampling - nur fuer Lernzwecke vertretbar, siehe Kommentar dort)management.zipkin.tracing.endpoint
api-gateway, config-server und discovery-server importieren den Config Server NICHT (siehe
deren application.yml-Kommentare) und haben deshalb ihre eigene, lokale Kopie dieser
Einstellungen - ein bewusster, dokumentierter Fall von "nicht ALLES zentralisierbar", siehe auch
ADR-0006.
Zentrales Logging: Grafana Loki + Promtail
infra/docker-compose.yml enthaelt zwei zusaetzliche Services:
- Promtail liest die Container-Logs direkt ueber Podmans Docker-kompatible API
(
docker_sd_configs, ueber den gemounteten Podman-Socket - automatische Service Discovery, kein statisches Target-Set wie bei Prometheus). Gefiltert wird perrelabel_configsauf Container mit dem Namenspraefixlibrary-(sieheinfra/promtail/promtail-config.yaml). - Loki speichert die eingesammelten Log-Zeilen und ist als zweite Grafana-Datasource
provisioniert (
infra/grafana/provisioning/datasources/loki.yml), analog zur bestehenden Prometheus-Datasource.
Alle neun Fachservices setzen in infra/docker-compose.yml die Umgebungsvariable
LOGGING_CONFIG: classpath:logback-json.xml - das schaltet Spring Boot auf die alternative
Logback-Konfiguration aus common-observability um (logback-json.xml, JSON-Zeilen via
LogstashEncoder, inklusive correlationId als eigenem JSON-Feld). Ohne diese Variable (z. B.
beim Start ueber die IDE, "Local"-Stufe) bleibt Spring Boots menschenlesbares Standardformat
aktiv - bewusst additiv, siehe Kommentar in logback-json.xml.
Ausprobieren
cd infra
podman compose up -d
# ein paar Anfragen ausloesen, z. B. ueber die Angular-Oberflaeche oder curl/Postman gegen
# das api-gateway (http://localhost:8080/api/books)
- Prometheus (http://localhost:9090): unter "Status → Targets" pruefen, ob alle neun Services
als "UP" gelistet sind. Eine Beispiel-Query:
http_server_requests_seconds_count(Anzahl HTTP- Requests pro Service/Pfad/Statuscode). - Grafana (http://localhost:3000, admin/admin): die Prometheus-Datasource ist bereits per
Provisioning verdrahtet (
infra/grafana/provisioning/datasources/prometheus.yml) - unter "Explore" direkt gegen Prometheus abfragen, oder ein eigenes Dashboard aus den Standard- Micrometer-Metriken bauen (jvm_memory_used_bytes,http_server_requests_seconds,process_cpu_usage, ...). Ein fertiges Dashboard mitzuliefern ist bewusst eine Vertiefungsaufgabe (Dashboards sind sehr geschmacks-/bedarfsabhaengig - ein selbst gebautes lehrt mehr als ein importiertes JSON). - Zipkin (http://localhost:9411): "Run Query" ohne Filter zeigt die zuletzt aufgezeichneten
Traces. Am aufschlussreichsten: einen
POST /api/loans(Ausleihe, siehe lending-service's Saga) suchen - der Trace zeigt sichtbar die Aufrufe an catalog-service UND member-service als Kindspans desselben Traces, inklusive Zeitanteilen (praktisch, um zu sehen, welcher der beiden Aufrufe den Request tatsaechlich dominiert). - Loki (ueber Grafana, http://localhost:3000 → "Explore" → Datasource "Loki"): das
container-Label enthaelt NUR den Servicenamen OHNE daslibrary--Praefix (Promtailsrelabel_configsininfra/promtail/promtail-config.yamlnutzt das Praefix nur zum FILTERN - andere, projektfremde Container auf derselben Maschine werden so herausgehalten - schneidet es fuer den eigentlichen Label-Wert aber wieder ab, siehe Kommentar dort). LogQL- Basis-Beispiele:{container=~".+"}- alle Log-Zeilen aller Fachservices (jedes Label matcht, aber LogQL verlangt mindestens einen nicht-leeren Matcher).{container="lending-service"} | json- nur lending-service, JSON-Felder (message,level,correlationId, ...) einzeln auswertbar/filterbar.{container=~".+"} | json | correlationId="<Wert>"- alle Log-Zeilen ueber ALLE Services hinweg zu einem einzelnen Request (Correlation-Id aus einem Response-Header oder einem Zipkin-Trace kopieren) - praktisch in Kombination mit der Zipkin-Ausprobieren-Zeile oben.{container=~".+"} |= "ERROR"- reiner Text-Filter, funktioniert auch ohne| json.
Warum keine Observability-Stack-Installation in Kubernetes
Das Helm-Chart (infra/helm/) deployt bewusst NUR die neun Anwendungsservices, nicht
Prometheus/Grafana/Zipkin selbst - in einem echten Cluster wuerden dafuer etablierte, fertige
Helm-Charts verwendet (kube-prometheus-stack, zipkin offizielles Chart), keine
selbstgeschriebenen. Das nachzubauen waere hier reine Infrastruktur-Uebung ohne zusaetzlichen
Lernwert gegenueber dem bereits vorhandenen Compose-Aufbau - siehe
kubernetes-guide.md fuer den Scope der Kubernetes-Phase.