Was Sentry ans Licht brachte: Observability, Stabilität und die Kosten der eigenen Codeüberwachung
Produktionsfehler zeigten ein Schema-Mismatch, fehlgeschlagene Transaktionswiederherstellung und wenig hilfreiche Logs. Wie ein kleines Team Backend-Fehler mit Sentry behob, Browser-Monitoring vorbereitete und Alarmrauschen begrenzte.
Früher investierten Engineering-Teams entweder zu viel in Observability – etwa eine ganze SRE-Abteilung, die Dashboards verdrahtete, die niemand las – oder sie ließen sie ganz weg und erfuhren erst durch eine Kundenmail vom Ausfall. 2026 ist keines der Extreme vertretbar. Sie müssen wissen, was kaputtgeht, ohne für ein Indie-Produkt Enterprise-Preise zu zahlen.
Dieser Einblick zeigt, wie unsere Sentry-Integration Produktionsfehler sichtbar machte, welche Änderungen daraus folgten und wie wir Monitoring konfigurierten, um Rauschen und Verbrauch zu begrenzen. Außerdem geht es darum, wie sich Observability-Tools für kleine Engineering-Teams entwickeln.
Warum Browserfehler keine Alerts auslösten
Unser Backend ist seit März mit Sentry verbunden. Die DSN liegt im Google Secret Manager, das Secret wird in Cloud Run eingebunden und sentry_sdk.init läuft bei jedem Start. E-Mail-Alerts kamen an. Von außen sah alles gut aus.
Intern war das nicht der Fall. Sentry war im Frontend überhaupt nicht eingebunden. Browser-Ausnahmen, Hydration-Fehler und Fehler beim Laden von Chunks blieben unsichtbar. Zudem landeten Python-Fehler des Backends in einem als javascript-nextjs bezeichneten Projekt, weil es das einzige Projekt in der Organisation war. Stacktraces sammelten sich am falschen Ort, die Gruppierung war nutzlos und das Dashboard zeigte Ereignisse in mehreren Sprachen durcheinander.
Bevor wir einzelne Fehler angingen, mussten wir Browser- und Backend-Ausfälle voneinander trennen.
Was die Daten zeigten
Wir riefen die Fehlerereignisse der letzten 90 Tage ab. Einige Muster fielen auf:
Ein historischer Vorfall, der sich selbst behoben hatte
Der häufigste Fehler im Zeitraum war ein Postgres-StringDataRightTruncation: 16 Ereignisse in 22 Sekunden, ausgelöst durch den Social-Signup-Endpunkt. Ursache war ein klassischer Schema-Drift: Die Modelldefinition erlaubte eine Biografie mit 800 Zeichen, die Produktionsdatenbank hatte aber noch VARCHAR(500) aus einer früheren Migration. Eine Person übermittelte eine etwas mehr als 500 Zeichen lange Biografie. Unsere Pydantic-Schicht akzeptierte sie, und das INSERT scheiterte.
Die Migration zur Erweiterung der Spalte auf 800 war bereits geschrieben und am nächsten Morgen ausgerollt worden. Das Grundproblem blieb jedoch bestehen: Modell und Datenbankschema können auseinanderlaufen, ohne dass es jemand bemerkt, bis ein Kunde darauf stößt.
Wir taten zwei Dinge. Erstens verschärften wir das Anfrage-Schema für die Social-Registrierung: Mit explizitem max_length für E-Mail, Anzeigename und Token wird problematischer Input sauber mit 422 zurückgewiesen, statt die Datenbank zu erreichen. Zweitens erweiterten wir unser DB-Integritätsskript: Es vergleicht nun information_schema.columns.character_maximum_length mit den vom Anwendungscode erwarteten Längen. Wenn eine künftige Migration eine Spalte kleiner macht, als das Modell liefern kann, schlägt die nächste Deployment-Prüfung fehl.
Eine Sitzung, die nicht zurückrollen wollte
Weiter unten fanden wir eine Abfolge: ein OperationalError: server closed the connection unexpectedly bei POST /v1/upload, gefolgt von mehreren PendingRollbackError aus demselben Codepfad. Postgres hatte die Verbindung während einer Abfrage getrennt, die SQLAlchemy-Sitzung war ungültig und der Upload-Dienst versuchte daraufhin, Teilergebnisse zu speichern. Jeder weitere Vorgang in dieser Sitzung ließ den Fehler kaskadieren.
Die Korrektur ist klein, aber leicht falsch umzusetzen. Fängt die Upload-Pipeline eine Ausnahme ab, führt sie jetzt als allerersten Schritt db.rollback() aus – in einem eigenen try/except, damit ein fehlschlagender Rollback den ursprünglichen Fehler nicht verdeckt. Danach läuft die Teilspeicher-Logik mit einer bereinigten Sitzung.
Logs, die sich selbst auslöschten
Der WebSocket-Finish-Handler protokollierte eine abgefangene Ausnahme mit err=%s. Bei den meisten Ausnahmen ist das hilfreich. Bei einigen Typen, deren __str__ eine leere Zeichenfolge zurückgibt, stand jedoch nur err= im Log. Sentry meldete dann einen fehlgeschlagenen Speichervorgang, ohne den Grund zu nennen.
Der Wechsel zu logger.exception(...) und err=%r kostete nichts und machte jedes künftige Ereignis aussagekräftig.
Rauschen, für das wir nicht zahlen wollten
Die übrigen Einträge in der Warteschlange waren keine Fehler in unserem Code. Uvloop wirft gelegentlich RuntimeError: unable to perform operation on <TCPTransport closed=True>, wenn ein Client die Verbindung mitten in SSL trennt. Das ist erwartetes Verhalten und nichts, was wir beheben können. Bei einem kostenlosen Kontingent von 5.000 Fehlern pro Monat wäre es verschwendetes Budget. Ein before_send-Filter verwirft jetzt Ereignisse mit genau diesen Ausnahme- und Wertmustern. Im Frontend gilt dasselbe für ResizeObserver loop limit exceeded und vergleichbares Browserrauschen.
Das kostenlose Kontingent gezielt nutzen
Sentrys aktueller Developer-Tarif umfasst laut Stand vom 13. Oktober 2026 kostenlos 5.000 Fehler, 5 Millionen Tracing-Spans und 50 Replays pro Monat. Tracing wird in Spans gemessen, nicht in den früheren Performance-Einheiten. Prüfen Sie den aktuellen Tarif und planen Sie Tracing separat; aktivieren Sie es erst mit einer passenden Sampling-Rate. Sentry-Preise
Unsere Einstellungen:
tracesSampleRate: 0in Backend und Frontend. Verteiltes Tracing ist nützlich, aber das Span-Volumen braucht ein eigenes, anhand der Nutzung bemessenes Budget. Bei einer konkreten Untersuchung können wir es mit einer niedrigen Sampling-Rate aktivieren.profilesSampleRate: 0im Backend, aus demselben Grund.- Session Replay im Frontend deaktiviert. Der Integrationscode bleibt vorhanden, beide Sampling-Raten stehen jedoch auf null. Braucht ein kritischer Fehler Replay-Kontext, können wir
replaysOnErrorSampleRateeinen Tag lang auf0.05setzen und anschließend wieder deaktivieren. before_send-Filter in beiden Laufzeitumgebungen verwerfen Ereignisse, von denen wir bereits wissen, dass sie nicht handlungsrelevant sind.
Die Backend-Änderungen verringerten das Rauschen bei relevanten Fehlern, während die Browser-SDK-Konfiguration für eine Aktivierung vorbereitet wurde. Das sind unterschiedliche Meilensteine: Weder Code noch Sampling-Einstellungen beweisen für sich, dass Browserereignisse im richtigen Projekt ankommen.
Was sich am Observability-Markt verändert
Wir haben auf das kostenlose Kontingent abgestimmt, weil es für ein gehostetes Produkt ungewöhnlich großzügig ist. Die wirtschaftlichen Rahmenbedingungen verändern sich jedoch.
In den vergangenen zwölf bis achtzehn Monaten hat sich einiges verschoben:
- Offene Standards verringern den Migrationsaufwand, beseitigen ihn aber nicht. OTLP-kompatible Instrumentierung kann die Bindung an ein Monitoring-Backend reduzieren. Herstellerspezifische Abfragen, Dashboards, Alert-Regeln und SDK-Funktionen müssen bei einem Wechsel weiterhin geplant und getestet werden.
- Self-Hosting verändert die Kostenrechnung. Optionen wie GlitchTip und OTLP-native Stacks bieten alternative Monitoring-Wege. Vergleichen Sie Speicher, Backups, Upgrades und Engineering-Zeit mit dem gehosteten Tarif, nicht nur eine VM-Rechnung mit dem Abonnementpreis.
- KI-gestütztes Debugging erweitert den Ablauf. Sentrys Seer schlägt Ursachen und Patches vor; eine autorisierte MCP-Integration kann Fehlerkontext an einen Programmierassistenten übergeben. Ein vorgeschlagener Fix braucht vor der Veröffentlichung dennoch Reproduktion und Regressionstests.
- Tarifgrenzen verdienen ebenso viel Aufmerksamkeit wie Funktionen. Fehleraufkommen, Aufbewahrungsdauer, Sampling und Teamzugriff können die Kosten beeinflussen. Beginnen Sie mit den nötigen Signalen und einem gemessenen Ereignisbudget und vergleichen Sie Tarife anhand dieser Auslastung.
Zum Stand dieses Release-Schnappschusses deckte Sentry unseren unmittelbaren Bedarf an Fehlermonitoring ab. Offene Schnittstellen geben dem Team künftig mehr Optionen. Ein Anbieterwechsel würde dennoch eine Prüfung von Projektrouting, Alerts, gespeicherten Daten und anbieterspezifischen Funktionen erfordern.
Deployment-Prüfungen vervollständigen das Monitoring
Zum Snapshot dieses Artikels vom 17. Mai 2026 standen zwei Deployment-Aufgaben noch aus:
- Ein eigenes Python-Sentry-Projekt anlegen, damit Backend-Fehler nicht mehr unter
javascript-nextjserfasst werden. Die DSN wird im selben Secret-Manager-Eintrag ersetzt, den das Backend bereits verwendet. - Die Frontend-DSN in den Projekteinstellungen von Vercel hinterlegen, damit clientseitige Fehler eingehen. Der Code ist bereits vorhanden und wird bedingt initialisiert; es fehlt nur die Umgebungsvariable.
Senden Sie bei jedem Monitoring-Rollout aus jeder Laufzeitumgebung ein kontrolliertes Testereignis und prüfen Sie Projekt, Umgebung, Gruppierung und Kontext, bevor Sie die Integration als abgeschlossen bezeichnen. Getrennte Projekte und eine Umgebungsvariable sind Einrichtungsschritte, kein Beleg dafür, dass Ereignisse angekommen sind.
Warum das wichtig ist
Wenn Sie nicht sehen, was kaputtgeht, investieren Sie entweder zu viel in defensive Programmierung oder zu wenig und veröffentlichen Fehler. Beides ist teuer. Günstige, zuverlässige Observability lässt ein kleines Team wie ein größeres arbeiten: Regressionen erkennen, bevor Kunden sie bemerken, sie ohne Rätselraten beheben und Engineering-Zeit in neue Funktionen investieren.
Die wichtigste Lehre: Prüfen Sie beide Seiten – sowohl die Korrekturen in der Anwendung als auch den Monitoring-Pfad, der die nächste Regression sichtbar machen soll.