Prometheus + Grafana + OpenTelemetry + Sentry: Die Integrations-Checkliste für einen produktionsreifen Observability-Stack
Die meisten Observability-Probleme sind keine Tool-Probleme. Es sind Integrationsprobleme. Prometheus scrapt Metriken, OpenTelemetry sendet Traces, Loki sammelt Logs und Sentry fängt Exceptions - aber jedes System lebt in seinem eigenen Silo. Um 2 Uhr nachts feuert ein Alert, und du verbringst zwanzig Minuten damit, Trace-IDs zwischen vier Browser-Tabs hin und her zu kopieren, um ein Bild zusammenzusetzen, das dein Tooling längst für dich hätte bauen sollen.
Dieser Beitrag liefert dir die Checkliste zur Prometheus Grafana OpenTelemetry Sentry Integration, die diese vier Systeme tatsächlich verbindet. Sie umfasst Collector-Konfiguration, SDK-Instrumentierung für Symfony und Next.js, die Verdrahtung der Grafana-Datasources, Alert-Routing vom Alertmanager zu Slack und PagerDuty sowie die drei Integrationsfehler, die Phantom-Alerts erzeugen - oder schlimmer: stille Ausfälle.
Der Vier-Schichten-Stack und wie die Teile zusammenpassen
Bevor wir in die Checkliste einsteigen, eine kurze Karte der Zuständigkeiten:
- Prometheus sammelt und speichert Zeitreihen-Metriken. Es scrapt
/metrics-Endpoints nach Zeitplan und wertet Alerting-Regeln aus. - Grafana visualisiert alles. Es dient als einheitliches Frontend für Prometheus, Loki, Tempo und - über das Sentry-Datasource-Plugin - deine Fehlervolumina.
- OpenTelemetry (OTel) ist die Instrumentierungsschicht. Das OTel-SDK in deiner Anwendung sendet Traces, Metriken und Logs. Der OTel Collector empfängt sie und leitet sie an die passenden Backends weiter (Tempo für Traces, Loki für Logs, Prometheus Remote-Write für Metriken).
- Sentry fängt Fehler, gruppiert sie zu Issues und trackt Releases. Seine größte Stärke sind Stacktraces mit Quellkontext und Regressionserkennung auf Release-Ebene.
Das Integrationsziel ist Korrelation: Wenn ein Grafana-Alert auf einer Prometheus-Metrik feuert, solltest du zu einem Tempo-Trace aus demselben Zeitfenster durchklicken können, die zugehörigen Loki-Logzeilen sehen und beim Sentry-Issue mit dem Stacktrace landen. Jeder Abschnitt unten bringt dich diesem Ziel einen Schritt näher.
Phase 1: Prometheus und der OTel Collector
Collector-Konfiguration
Der OTel Collector ist die zentrale Routing-Drehscheibe. Betreibe ihn als Sidecar oder als eigenen Service; Letzteres skaliert besser.
Checkliste:
- Deploye
otelcol-contrib(nicht den Core-Build - du brauchst den Prometheus-Exporter und den Loki-Exporter) - Konfiguriere einen
prometheus-Receiver auf Port9464, der den/metrics-Endpoint deiner Anwendung scrapt - Konfiguriere einen
otlp-Receiver (gRPC auf4317, HTTP auf4318) für Traces und Logs aus dem SDK - Ergänze einen
batch-Processor mitsend_batch_size: 1024undtimeout: 5s, um die Backends nicht mit winzigen Payloads zu fluten - Ergänze einen
memory_limiter-Processor mit 80% des Container-Memory-Limits - ohne ihn läuft der Collector in Produktion in ein OOM - Route Trace-Daten an einen
otlp-Exporter Richtung Tempo - Route Log-Daten an einen
loki-Exporter - Route Metriken an einen
prometheusremotewrite-Exporter Richtung deiner Prometheus-Instanz (oder Mimir / Thanos bei horizontaler Skalierung)
Der häufigste Fehler hier: prometheusremotewrite nutzen und gleichzeitig einen separaten Prometheus-Scrape-Job für denselben Service laufen lassen. Das erzeugt doppelte Zeitreihen und erratische Rate-Berechnungen. Entscheide dich für einen Ingestion-Pfad.
Prometheus-Scrape-Konfiguration
Eine minimale Scrape-Konfiguration, die Label-Kollisionen vermeidet:
scrape_configs:
- job_name: 'otel-collector'
static_configs:
- targets: ['otel-collector:8888']
- job_name: 'your-app'
static_configs:
- targets: ['app:9464']
honor_labels: true
scrape_interval: 15s
Prüfe, dass die Prometheus-Seite /targets alle Jobs als UP zeigt, bevor du zu den Alerting-Regeln weitergehst.
Phase 2: SDK-Instrumentierung in Symfony und Next.js
Symfony (PHP)
Nutze open-telemetry/opentelemetry-auto-symfony für die automatische Instrumentierung von HTTP-Requests, Doctrine-Queries und Messenger-Dispatches.
composer require open-telemetry/sdk open-telemetry/opentelemetry-auto-symfony
Die wichtigsten Umgebungsvariablen für .env.prod:
OTEL_SERVICE_NAME=your-app-name
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_TRACES_SAMPLER=parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARG=0.1
Checkliste:
- Prüfe, dass
ext-opentelemetryin derphp.inigeladen ist - das Auto-Instrumentierungspaket benötigt die C-Extension - Ergänze eigene Spans für geschäftskritische Codepfade, die nicht automatisch instrumentiert werden (z. B. Preisberechnungen, Aufrufe von Dritt-APIs): nutze
$tracer->spanBuilder('pricing.calculate')->startSpan() - Bestätige, dass Traces innerhalb von 30 Sekunden nach einem Test-Request in Tempo erscheinen
Next.js (Node)
npm install @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node
Checkliste:
- Lege
instrumentation.tsim Projekt-Root an (Next.js 14+ registriert die Datei automatisch) - Initialisiere das
NodeSDKmit einem OTLP-Exporter, der auf den Collector zeigt - Setze
OTEL_SERVICE_NAMEundOTEL_RESOURCE_ATTRIBUTES=deployment.environment=productionin deiner Umgebungskonfiguration - Nutze
registerInstrumentationsmitgetNodeAutoInstrumentations()- das deckt HTTP, fetch, Datenbank-Clients und Redis automatisch ab - Verifiziere die Spans in Tempo. Wenn du Spans ohne Parent siehst (kaputter Trace-Baum), prüfe, ob
traceparent-Header zwischen den Services propagiert werden - der W3C-Trace-Context-Propagator muss auf beiden Seiten konfiguriert sein
Phase 3: Grafana-Datasources verdrahten
Eine Grafana-Instanz, die nur Prometheus-Daten zeigt, ist halb verbunden. Das vollständige Setup braucht vier Datasources und zwei Exemplar-Links.
Checkliste:
- Prometheus-Datasource hinzufügen - als Default markieren
- Tempo-Datasource hinzufügen,
Trace to logsauf Loki zeigen lassen mittraceIdals Log-Label-Filter - Loki-Datasource hinzufügen, über
Derived fieldsdietraceIdaus Logzeilen extrahieren und nach Tempo verlinken - In der Prometheus-Datasource
Exemplarsaktivieren und das URL-Template auf Tempo setzen - so kannst du auf eine Spitze im Latenz-Histogramm klicken und direkt zu einem Beispiel-Trace springen - Das Sentry-Datasource-Plugin (
grafana-sentry-datasource) installieren und mit einem Sentry-Auth-Token verbinden, das aufproject:readbeschränkt ist - Prüfe im
Explore-Tab, dass jede Datasource Daten liefert, bevor du Dashboards baust
Die zehn Panels, die jeder Service zum Launch braucht
Füge diese in ein einzelnes Dashboard pro Service ein. Sie decken die Signale ab, die zählen, bevor du dir vollumfängliches Observability-Engineering leisten kannst:
- Request-Rate -
rate(http_server_requests_total[5m]) - Fehlerrate (%) - Fehler geteilt durch Gesamtanzahl der Requests
- p50 / p95 / p99 Latenz - aus dem Histogramm
http_request_duration_seconds_bucket - Aktive DB-Verbindungen
- Queue-Tiefe - falls Symfony Messenger oder eine Background-Job-Queue im Einsatz ist
- Speicherverbrauch vs. Limit
- CPU-Throttling - signalisiert Ressourcendruck im Container, bevor er zum Latenzproblem wird
- Sentry-Fehlervolumen - Issues pro Minute aus der Sentry-Datasource
- Deployment-Marker - annotiert aus der CI/CD über die Grafana-Annotations-API, damit du auf jedem Graphen exakt siehst, wann ein neues Release gelandet ist
- Apdex-Score - eine einzelne, menschenlesbare Zahl, die Latenz und Fehlerrate kombiniert
Phase 4: Alertmanager und Sentry Release-Tracking
Alertmanager zu Slack und PagerDuty
Prometheus wertet Alerting-Regeln aus; der Alertmanager übernimmt Routing, Deduplizierung und Silencing.
Checkliste:
- Definiere Alerting-Regeln in einem
rules/-Verzeichnis, das in Prometheus gemountet wird, nicht inline in derprometheus.yml- so lassen sie sich leichter in Git nachverfolgen - Starte mit vier Regeln:
HighErrorRate(>1% für 5 Min.),HighLatency(p95 >1 s für 5 Min.),ServiceDown(up == 0 für 1 Min.),HighMemoryUsage(>90% für 10 Min.) - Konfiguriere Alertmanager-
routes, die Alerts mitseverity: criticalan PagerDuty undseverity: warningan einen Slack-Channel senden - Setze
group_wait: 30s,group_interval: 5m,repeat_interval: 4h- die Defaults sind zu aggressiv und erzeugen innerhalb einer Woche Alert-Müdigkeit - Ergänze Inhibition-Regeln: Unterdrücke
HighErrorRateundHighLatency, wenn für denselben Service bereitsServiceDownfeuert - du brauchst keine drei gleichzeitigen Pages für einen Ausfall
Sentry Release-Tracking
Sentrys Release-Tracking wird zu selten genutzt, ist aber essenziell, um "dieser Bug existiert seit Wochen" von "diese Regression kam mit dem heutigen Deploy" zu unterscheiden.
Checkliste:
- Setze
SENTRY_RELEASEin deiner CI/CD-Pipeline auf den Git-Commit-SHA (oder nutzesentry-cli releases propose-version) - Rufe am Ende eines erfolgreichen Deploys
sentry-cli releases finalize $RELEASEauf - Lade Source Maps aus dem Next.js-Build zu Sentry hoch, damit Stacktraces originales TypeScript statt minifiziertem Output zeigen
- Konfiguriere
traces_sample_rateim Sentry-SDK passend zu deiner OTel-Sampling-Rate - wenn OTel 10% sampelt und Sentry 100%, siehst du Performance-Transaktionen ohne korrespondierenden OTel-Trace - Aktiviere in den Sentry-Projekteinstellungen
Connect tracesund hinterlege das Tempo-URL-Muster, um direkte Links zwischen einem Sentry-Trace und dem zugehörigen Tempo-Trace zu erzeugen
Die drei Integrationsfehler, die Phantom-Alerts erzeugen
Nach Audits von Observability-Stacks bei SaaS-Kunden in verschiedenen Wachstumsphasen tauchen drei Konfigurationsfehler immer wieder auf.
1. Unterschiedliche Sampling-Raten zwischen den Tools. OTel mit 10% Sampling und Sentry mit 100% ist der häufigste Übeltäter. Sentry fängt einen Fehler, erzeugt einen sentry-trace-Header und versucht, ihn mit einem OTel-Trace zu korrelieren, der nie gesampelt wurde. Das Ergebnis: kaputte Trace-Links und der falsche Eindruck, dein Tracing sei defekt, obwohl nur die Tool-Konfiguration nicht abgestimmt ist.
Lösung: Setze OTEL_TRACES_SAMPLER_ARG und Sentrys traces_sample_rate auf denselben Wert, oder nutze Sentry als Tail-based Sampler hinter OTel.
2. Clock Skew zwischen Containern. Traces, die aus Spans verschiedener Container rekonstruiert werden, brauchen konsistente Zeitstempel. Ein Container, dessen Uhr auch nur um 200 ms abweicht, produziert Traces mit überlappenden Spans oder negativer Dauer. Das sieht aus wie ein Instrumentierungsfehler, ist aber ein Infrastrukturproblem.
Lösung: Stelle sicher, dass alle Container die NTP-synchronisierte Uhr des Hosts nutzen. In Kubernetes passiert das automatisch; in reinem Docker Compose nicht - und genau da erwischt es Teams unvorbereitet.
3. Label-Kardinalitätsexplosion durch Trace-IDs in Prometheus. Wenn du versehentlich eine Trace-ID, Request-ID oder User-ID als Prometheus-Label aufnimmst, erzeugst du eine eigene Zeitreihe pro Request. Prometheus wird quälend langsam und läuft irgendwann in ein Out-of-Memory.
Lösung: Auditiere dein Label-Set vor dem Produktions-Deployment. Jedes Label mit unbegrenztem Wertebereich muss im Collector oder in der Metrik-Schicht der Anwendung entfernt werden, bevor Prometheus es aufnimmt. Der transform-Processor des OTel Collectors kann gezielt Attribute aus Metriken entfernen, bevor sie Prometheus erreichen.
Der Referenz-Stack mit docker-compose
Für lokale Entwicklung und Staging verdrahtet dieses minimale Compose-File alle vier Tools. Passe Ressourcenlimits und Storage-Volumes an, bevor du es in Produktion einsetzt.
services:
prometheus:
image: prom/prometheus:v2.51.0
volumes:
- ./config/prometheus.yml:/etc/prometheus/prometheus.yml
- ./config/rules:/etc/prometheus/rules
ports: ["9090:9090"]
grafana:
image: grafana/grafana:10.4.2
environment:
- GF_INSTALL_PLUGINS=grafana-sentry-datasource
ports: ["3001:3000"]
depends_on: [prometheus, loki, tempo]
otel-collector:
image: otel/opentelemetry-collector-contrib:0.99.0
volumes:
- ./config/otel-collector.yaml:/etc/otel/config.yaml
command: ["--config", "/etc/otel/config.yaml"]
ports: ["4317:4317", "4318:4318", "8888:8888"]
tempo:
image: grafana/tempo:2.4.1
command: ["-config.file=/etc/tempo.yaml"]
volumes:
- ./config/tempo.yaml:/etc/tempo.yaml
loki:
image: grafana/loki:2.9.7
ports: ["3100:3100"]
Es gleich beim ersten Mal richtig machen
Diesen Stack von Grund auf zu bauen kostet zwei bis drei Tage sorgfältiger Konfiguration. Ihn falsch zu bauen - nicht abgestimmtes Sampling, unbegrenzte Label-Kardinalität, isoliertes Alerting - bedeutet Observability-Tooling, das dir beim Debuggen von Produktionsvorfällen nicht wirklich schneller hilft. Der Wert eines verbundenen Stacks zeigt sich erst, wenn du in unter fünf Minuten von einem Alert zur Ursache kommst.
Wenn du eine Symfony- oder Next.js-Anwendung instrumentierst und eine zweite Meinung zu deinem aktuellen Setup möchtest - oder diesen Stack von Anfang an gebaut und validiert brauchst - ist hello@wolf-tech.io der richtige Startpunkt. Observability-Architektur ist auch Teil unserer Beratungen zu Code-Qualität und individueller Anwendungsentwicklung auf wolf-tech.io.

