Logging, Tracing und Correlation IDs
Intermittierende GraphQL-Fehler sind schwer zu reproduzieren, weil der Kontext fehlt. Strukturiertes Logging, Request-Tracing und Correlation IDs machen jeden Fehler nachvollziehbar – auch Tage nach dem Auftreten, auch über mehrere Resolver-Ketten hinweg.
Inhaltsverzeichnis
- 1. Warum intermittierende GraphQL-Fehler besonders schwer zu debuggen sind
- 2. Correlation IDs: jeden Request eindeutig identifizieren
- 3. Strukturiertes Logging in GraphQL-Resolvern
- 4. Resolver-Tracing: Ausführungszeit und Pfad nachvollziehen
- 5. Magento-Logs für GraphQL-Fehler auswerten
- 6. extensions.debug: Kontext in der Fehlerantwort zurückgeben
- 7. Fehler-Reproduktion: Query, Kontext und Variablen rekonstruieren
- 8. Logging-Strategien im Vergleich
- 9. Typische Observability-Lücken in Magento-GraphQL-Projekten
- 10. Zusammenfassung
- 11. FAQ
1. Warum intermittierende GraphQL-Fehler besonders schwer zu debuggen sind
Ein intermittierender Fehler tritt auf, aber nicht reproduzierbar. Wenn ein Nutzer meldet, dass der Checkout fehlgeschlagen ist, und der Fehler seitdem nicht mehr auftritt, beginnt eine Debugging-Session, die ohne Kontext meist erfolglos bleibt. Was war der genaue Query? Welche Variablen wurden übergeben? War der Nutzer eingeloggt? Welcher Resolver hat die Exception geworfen? Ohne Logging und Tracing sind all das unbeantwortete Fragen.
GraphQL verschärft dieses Problem gegenüber REST, weil alle Anfragen über denselben Endpunkt laufen. In Logs erscheinen nur POST-Anfragen auf /graphql, ohne Information darüber, welche Operation ausgeführt wurde. In Magento-Logs stehen PHP-Exceptions mit Stacktraces, aber ohne den zugehörigen GraphQL-Query oder die Variablen. Das Ergebnis: Fehler, die in der Produktionsumgebung auftreten, können in Entwicklung nicht nachgestellt werden, weil der Kontext fehlt, der den Fehler überhaupt erst ausgelöst hat.
2. Correlation IDs: jeden Request eindeutig identifizieren
Eine Correlation ID ist ein eindeutiger Bezeichner, der zu Beginn jedes Requests erzeugt oder vom Client mitgeschickt und dann durch alle Logging-Schichten weitergegeben wird. Das Muster: Der Client sendet entweder einen X-Correlation-ID-Header, oder der Server erzeugt beim Empfang des Requests eine UUID und gibt sie als Response-Header zurück. Alle Log-Einträge, die zu diesem Request gehören – GraphQL-Resolver, Datenbankabfragen, Cache-Zugriffe – werden mit dieser ID getaggt.
Das ermöglicht, in einem zentralen Log-System alle Einträge eines bestimmten fehlerhafte Requests zu finden, indem man nach der Correlation ID filtert. Aus dem errors-Array einer GraphQL-Antwort wird die Correlation ID als Teil des extensions-Objekts zurückgegeben – der Client kann sie dem Nutzer als Referenznummer anzeigen, die der Support dann im Log-System nachschlagen kann. Ohne Correlation IDs ist jeder Produktionsfehler eine Suche nach der Nadel im Heuhaufen.
# GraphQL error response with correlation ID in extensions
# Client sends X-Correlation-ID header or server generates it
# Request header:
# X-Correlation-ID: 550e8400-e29b-41d4-a716-446655440000
# Error response with correlation ID attached to extensions:
{
"errors": [
{
"message": "Ein Fehler ist aufgetreten. Bitte versuchen Sie es erneut.",
"extensions": {
"category": "graphql-no-such-entity",
"correlation_id": "550e8400-e29b-41d4-a716-446655440000"
}
}
],
"data": { "product": null }
}
# Support workflow:
# User reports: "Fehler mit Referenz 550e8400..."
# Support searches logs: grep "550e8400" /var/log/magento/graphql.log
# All resolver calls, DB queries, cache misses for this request visible
3. Strukturiertes Logging in GraphQL-Resolvern
Strukturiertes Logging bedeutet, Log-Einträge als JSON-Objekte zu schreiben statt als Freitext-Strings. Das ermöglicht es, Log-Aggregatoren wie Elasticsearch, Loki oder CloudWatch Logs nach bestimmten Feldern zu filtern und zu aggregieren. Ein strukturierter Log-Eintrag für einen GraphQL-Resolver enthält mindestens: Zeitstempel, Log-Level, Operation-Name, Resolver-Pfad, Ausführungszeit und Correlation ID. Fehler-Einträge enthalten zusätzlich die Exception-Klasse, die Nachricht und den Stacktrace.
In Magento kann strukturiertes Logging über Monolog implementiert werden, das bereits in Magento integriert ist. Der Processor-Mechanismus von Monolog erlaubt, Correlation ID und Request-Kontext automatisch jedem Log-Eintrag hinzuzufügen, ohne dass jeder Resolver explizit diese Information übergeben muss. Ein dedizierter GraphQL-Logger-Kanal mit eigenem Log-File (var/log/graphql.log) trennt GraphQL-spezifische Logs von den allgemeinen Magento-Logs und erleichtert die gezielte Auswertung.
4. Resolver-Tracing: Ausführungszeit und Pfad nachvollziehen
GraphQL-Resolver werden in einer Baumstruktur ausgeführt, und Leistungsprobleme entstehen oft in einem Zweig des Baums, der viele Datenbankabfragen verursacht. Resolver-Tracing erfasst für jeden Resolver den Ausführungszeitpunkt (Start, Ende, Dauer) und den Pfad im Query-Baum. Das Ergebnis ist ein vollständiges Profil der Resolver-Ausführung, aus dem sofort ersichtlich ist, welcher Resolver die meiste Zeit benötigt hat.
Der GraphQL-Standard für Tracing ist die tracing-Extension, die von Apollo Server implementiert wird und im extensions.tracing-Feld der GraphQL-Antwort erscheint. In Magento ist Resolver-Tracing nicht eingebaut, kann aber durch eigene Middleware oder Resolver-Wrapper implementiert werden. Für Produktionssysteme ist Tracing typischerweise ausgeschaltet (zu viel Overhead und Informationsleck) und wird nur auf Anfrage oder in Staging-Umgebungen aktiviert. OpenTelemetry ist die zukunftssichere Lösung für Distributed Tracing, die Resolver-Zeitprofile mit dem übergeordneten Request-Kontext verbindet.
5. Magento-Logs für GraphQL-Fehler auswerten
Magento schreibt GraphQL-Fehler in mehrere Log-Dateien, abhängig von der Art des Fehlers. PHP-Exceptions, die nicht von einem GraphQL-Exception-Handler abgefangen werden, landen in var/log/exception.log. Resolver-spezifische Fehler können in var/log/system.log erscheinen, wenn der Resolver explizit auf den System-Logger schreibt. In Developer-Mode erscheint der Stacktrace zusätzlich im extensions-Objekt der GraphQL-Fehlerantwort.
Ein Problem bei der Magento-Log-Auswertung: Die Logs enthalten keine Information darüber, welcher GraphQL-Query die Exception ausgelöst hat. Man sieht den Stacktrace des PHP-Fehlers, aber nicht den Query-Text, die Variablen oder die Nutzer-ID. Eine Verbesserung: In einem Request-Plugin den GraphQL-Query und die Operation-Name aus dem Body lesen und als Kontext-Information an den Logger übergeben, bevor die Resolver ausgeführt werden. Dann erscheint der Operation-Name in jedem Log-Eintrag dieses Requests.
# GraphQL operation logging — structured log entry pattern
# Written at request start (before resolver execution)
# Log entry format (JSON structured logging via Monolog):
# {
# "timestamp": "2026-05-09T14:23:11Z",
# "level": "INFO",
# "channel": "graphql",
# "message": "GraphQL request received",
# "context": {
# "correlation_id": "550e8400-e29b-41d4-a716-446655440000",
# "operation_name": "GetCustomerOrders",
# "operation_type": "query",
# "customer_id": 42,
# "ip": "203.0.113.5"
# }
# }
# Query that triggered the error (also logged):
query GetCustomerOrders($pageSize: Int = 10) {
customer {
orders(pageSize: $pageSize) {
items {
order_number
status
grand_total { value currency }
}
}
}
}
# Variables logged alongside (never log sensitive fields like passwords):
# { "pageSize": 10 }
6. extensions.debug: Kontext in der Fehlerantwort zurückgeben
In Entwicklungsumgebungen ist es nützlich, Debug-Informationen direkt im extensions-Objekt der Fehlerantwort zurückzugeben – ohne dass der Entwickler sich in die Log-Datei einloggen muss. Magento macht das im Developer-Mode bereits: Der Stacktrace erscheint als extensions.trace. Darüber hinaus können eigene Debug-Informationen hinzugefügt werden: welcher Resolver den Fehler geworfen hat, wie viele Datenbankabfragen ausgeführt wurden, welche Cache-Einträge verfehlt wurden.
Wichtig: Debug-Extensions dürfen in der Produktionsumgebung nicht zurückgegeben werden. Stacktraces und interne Systeminformationen sind ein Sicherheitsrisiko, weil sie Angreifern Informationen über die interne Architektur liefern. Die saubere Implementierung: Debug-Extensions sind konfigurationsabhängig und werden nur aktiviert, wenn die Umgebungsvariable MAGE_MODE=developer gesetzt ist. In Produktion enthält das extensions-Objekt nur die Correlation ID und die Fehlerkategorie.
7. Fehler-Reproduktion: Query, Kontext und Variablen rekonstruieren
Die vollständige Reproduktion eines Produktionsfehlers erfordert drei Informationsquellen: den exakten GraphQL-Query-Text (inklusive Fragmenten), die Variablen, die mitgeschickt wurden, und den Kontext (Nutzer-ID, Session-Status, Zeitpunkt). Wenn diese drei Informationen geloggt werden, kann jeder Produktionsfehler in einer Entwicklungsumgebung reproduziert werden – durch einfaches Einspielen des geloggten Requests in ein Debugging-Tool wie Altair oder durch ein Replay-Script.
Für das Logging von Queries gibt es einen Kompromiss: Queries können groß sein (bei verschachtelten Selections mit Fragments) und erzeugen dann erhebliches Log-Volumen. Ein pragmatischer Ansatz: Den Operation-Name und die Variablen immer loggen (beide sind klein), den vollständigen Query-Text nur bei Fehlern loggen. Das reduziert das Log-Volumen im Normalbetrieb und stellt trotzdem die notwendige Information für die Fehlerreproduktion bereit. Für Persisted Queries, bei denen der Client eine Query-ID statt des Query-Textes sendet, ist die Query-ID ausreichend – der Text ist auf dem Server bekannt.
8. Logging-Strategien im Vergleich
Unterschiedliche Logging-Ansätze bieten unterschiedliche Suchbarkeit, Overhead und Implementierungsaufwand. Die richtige Strategie hängt von der Infrastruktur und den Debugging-Anforderungen ab.
| Strategie | Suchbarkeit | Overhead | Reproduzierbarkeit |
|---|---|---|---|
| Kein Logging | Keine | Null | Nicht möglich |
| Magento exception.log | Stacktrace, kein Query | Minimal | Kontext fehlt |
| Strukturiertes Logging + Correlation ID | Vollständig | Gering | Hoch |
| Resolver-Tracing (immer) | Sehr hoch | Hoch | Sehr hoch |
| OpenTelemetry Sampling | Hoch (Stichprobe) | Moderat | Hoch |
Für die meisten Magento-Projekte ist strukturiertes Logging mit Correlation ID die beste Balance: geringer Overhead, vollständige Suchbarkeit und hohe Reproduzierbarkeit von Fehlern. Resolver-Tracing ist für Performance-Debugging in Staging-Umgebungen wertvoll, aber zu aufwändig für den kontinuierlichen Produktionsbetrieb. OpenTelemetry-Sampling ist die Lösung für hochvolumige Systeme, bei denen selbst strukturiertes Logging jeden Requests zu viel Log-Volumen erzeugen würde.
9. Typische Observability-Lücken in Magento-GraphQL-Projekten
Die häufigste Lücke ist das Fehlen des Operation-Names in den Logs. Alle GraphQL-Anfragen erscheinen als POST auf /graphql, was die Log-Suche nach spezifischen Operationen unmöglich macht. Die Lösung ist einfach: Den Operation-Name aus dem Request-Body lesen und als Kontext-Information dem Logger übergeben. Das ist eine einmalige Implementierung in einem Request-Plugin oder Middleware-Layer, die dann für alle GraphQL-Requests greift.
Eine zweite häufige Lücke ist das Fehlen von Variablen-Logging bei Fehlern. Wenn ein Fehler nur mit bestimmten Variablen-Kombinationen auftritt (z.B. bei einer bestimmten Produkt-ID oder einem bestimmten Promo-Code), ist der Fehler ohne die Variablen nicht reproduzierbar. Gleichzeitig sollten Variablen nicht ungefiltert geloggt werden – Passwörter und Kreditkarteninformationen müssen aus dem Log-Eintrag entfernt werden. Ein Variablen-Sanitizer, der bekannte sensitive Felder durch Platzhalter ersetzt, ist die richtige Lösung.
# Variable sanitization before logging — never log sensitive fields
# Raw variables from request (DO NOT log as-is):
# {
# "email": "customer@example.com",
# "password": "secretpass123",
# "cart_id": "abc123",
# "payment": { "code": "checkmo", "cc_number": "4111111111111111" }
# }
# Sanitized variables for logging (safe to store):
# {
# "email": "customer@example.com",
# "password": "[REDACTED]",
# "cart_id": "abc123",
# "payment": { "code": "checkmo", "cc_number": "[REDACTED]" }
# }
# Sensitive field list to always redact:
# password, currentPassword, newPassword, cc_number, cvv, token (auth tokens)
# Correlation ID in GraphQL extension for user-facing error reference:
query CheckoutQuery($cartId: String!) {
cart(cart_id: $cartId) {
items { product { name } quantity }
prices { grand_total { value currency } }
}
}
# correlation_id: "550e8400-..." returned in extensions on error
# User sees reference number, support looks up in logs
10. Zusammenfassung
GraphQL-Fehler reproduzierbar zu machen ist ein Infrastrukturproblem, kein Debugging-Problem. Ohne Correlation IDs, strukturiertes Logging und den Operation-Namen in den Logs ist jeder intermittierende Produktionsfehler eine Raterei. Die Implementierung ist einmalig: Ein Request-Plugin, das Operation-Name, Correlation ID und sanitisierte Variablen loggt, macht alle zukünftigen Fehler nachvollziehbar – ohne dass jeder Resolver zusätzliche Logging-Logik implementieren muss.
Für Magento-Projekte sind die wichtigsten Maßnahmen: einen dedizierten GraphQL-Logger-Kanal einrichten, Correlation IDs als Response-Header und in Fehler-Extensions zurückgeben, Operation-Namen in allen Log-Einträgen aufnehmen und Variablen bei Fehlern geloggt (sanitisiert) zu halten. Resolver-Tracing und OpenTelemetry sind sinnvolle Erweiterungen für wachsende Systeme, aber keine Voraussetzung für grundlegende Reproduzierbarkeit von Produktionsfehlern.
GraphQL Fehler reproduzierbar machen — Das Wichtigste auf einen Blick
Correlation ID
Eindeutiger Bezeichner pro Request, durch alle Logging-Schichten weitergegeben. In Fehler-Extensions zurückgeben – ermöglicht gezieltes Log-Suchen nach Nutzer-Reports.
Operation-Name loggen
Alle GraphQL-Anfragen erscheinen als POST /graphql. Operation-Name aus dem Body lesen und in jeden Log-Eintrag aufnehmen – einmalige Implementierung im Request-Plugin.
Variablen sanitisieren
Variablen bei Fehlern loggen, aber sensitive Felder (password, cc_number) durch [REDACTED] ersetzen. Fehlerlogs ohne Variablen ermöglichen keine Reproduktion.
Debug nur in Dev
extensions.debug mit Stacktrace und internen Informationen nur im Developer-Mode. In Produktion nur Correlation ID und Fehlerkategorie in extensions.