engineering6 min czytania

Co pokazał Sentry: obserwowalność, stabilność i koszt pilnowania własnego kodu

Błędy produkcyjne ujawniły niezgodność schematu, nieudane odzyskiwanie transakcji i nieprzydatne logi. Jak mały zespół naprawił błędy backendu przy użyciu Sentry, przygotował monitoring przeglądarki i ograniczył szum alertów.

K
Ken Jo

Obserwowalność była kiedyś czymś, w co zespoły inżynierskie albo inwestowały za dużo — cały dział SRE konfigurował pulpity, których nikt nie czytał — albo całkiem ją pomijały i dowiadywały się o awarii usługi z wiadomości od klienta. W 2026 roku żadna skrajność nie jest do przyjęcia. Trzeba wiedzieć, co się psuje, ale bez płacenia korporacyjnych stawek za niezależny produkt.

Ten opis pokazuje, jak nasza integracja z Sentry ujawniła błędy produkcyjne, co zmieniliśmy w odpowiedzi i jak skonfigurowaliśmy monitoring, aby kontrolować szum oraz zużycie limitów. Przygląda się też zmianom na rynku narzędzi obserwowalności dla małych zespołów inżynierskich.

Dlaczego alerty nie pokazywały błędów przeglądarki

Od marca nasz backend był połączony z Sentry. DSN znajdował się w Google Secret Manager, sekret był montowany w Cloud Run, a sentry_sdk.init uruchamiał się przy każdym starcie. Alerty e-mail przychodziły. Z zewnątrz wszystko wyglądało poprawnie.

W środku było inaczej. Frontend w ogóle nie był podłączony do Sentry. Wyjątki przeglądarki, błędy hydratacji i problemy z ładowaniem fragmentów kodu pozostawały niewidoczne. Backend wysyłał też błędy Pythona do projektu javascript-nextjs, bo był to jedyny projekt w organizacji. Ślady stosu trafiały w niewłaściwe miejsce, grupowanie nie pomagało, a pulpit stał się strumieniem zdarzeń z różnych języków.

Najpierw trzeba było rozdzielić awarie przeglądarki od błędów backendu, dopiero potem zajmować się poszczególnymi usterkami.

Co pokazały dane

Pobraliśmy zdarzenia błędów z ostatnich dziewięćdziesięciu dni. Wyróżniło się kilka wzorców.

Dawny incydent, który sam się naprawił

Najczęściej występującym błędem w tym okresie był błąd Postgresa StringDataRightTruncation — szesnaście zdarzeń w ciągu dwudziestu dwóch sekund — pochodzący z endpointu rejestracji przez serwis społecznościowy. Przyczyną był klasyczny rozjazd schematu: definicja modelu dopuszczała biogram o długości 800 znaków, ale kolumna w bazie produkcyjnej nadal miała VARCHAR(500) po wcześniejszej migracji. Użytkownik przesłał biogram nieco dłuższy niż 500 znaków, warstwa Pydantic go zaakceptowała, a INSERT zakończył się błędem.

Migracja zwiększająca długość kolumny do 800 była już przygotowana i wdrożona następnego ranka. Pozostał jednak problem źródłowy: model i schemat bazy mogą się rozjechać, zanim ktokolwiek to zauważy — dopiero gdy trafi na to klient.

Zrobiliśmy dwie rzeczy. Po pierwsze, zaostrzyliśmy schemat żądania rejestracji przez serwis społecznościowy: ustawiliśmy jawne max_length dla adresu e-mail, nazwy wyświetlanej i tokenu, dzięki czemu patologiczne dane zwracają czyste 422, zamiast docierać do bazy. Po drugie, rozszerzyliśmy skrypt integralności bazy o porównywanie information_schema.columns.character_maximum_length z długościami oczekiwanymi przez aplikację. Jeśli przyszła migracja skróci kolumnę poniżej wartości dopuszczanej przez model, kontrola integralności zatrzyma kolejne wdrożenie.

Sesja, której nie dało się wycofać

Dalej na liście pojawiła się sekwencja: jeden OperationalError: server closed the connection unexpectedly przy POST /v1/upload, a następnie seria PendingRollbackError z tej samej ścieżki kodu. Postgres zerwał połączenie w trakcie zapytania, sesja SQLAlchemy znalazła się w nieprawidłowym stanie, a usługa przesyłania próbowała zapisać częściowy wynik na jej podstawie. Każda kolejna operacja w tej sesji kaskadowo kończyła się błędem.

Poprawka jest niewielka, ale łatwo ją źle zaimplementować. Gdy potok przesyłania przechwytuje wyjątek, pierwszą czynnością jest teraz db.rollback() — w osobnym try/except, aby nieudany rollback nie przesłonił pierwotnego błędu. Dopiero potem logika częściowego zapisu działa na czystej sesji.

Logi, które same się wymazywały

Obsługa końca WebSocketu logowała przechwycony wyjątek jako err=%s. Dla większości wyjątków daje to przydatny opis. Jednak kilka typów ma metodę __str__, która zwraca pusty tekst, więc log zawierał samo err=. Zdarzenia w Sentry informowały, że zapis się nie powiódł, ale nie podawały przyczyny.

Zamiana na logger.exception(...) i err=%r nic nie kosztowała, a sprawiła, że każde przyszłe zdarzenie zawierało potrzebne szczegóły.

Nie chcieliśmy płacić za szum

Pozostałe pozycje w kolejce nie były błędami. Uvloop czasem zgłasza RuntimeError: unable to perform operation on <TCPTransport closed=True>, gdy klient rozłącza się w trakcie SSL. To prawidłowe zachowanie, którego nie możemy naprawić, a przy limicie bezpłatnego planu wynoszącym 5 000 błędów miesięcznie zużywałoby budżet. Dodaliśmy filtr before_send, który odrzuca zdarzenia pasujące do tych konkretnych wzorców wyjątków i wartości. Podobnie na frontendzie odfiltrowaliśmy ResizeObserver loop limit exceeded i podobny szum przeglądarki.

Konfiguracja bezpłatnego planu

Według stanu na 13 października 2026 r. bezpłatny plan Sentry Developer obejmuje 5 000 błędów, 5 milionów spanów śledzenia i 50 nagrań miesięcznie. Śledzenie mierzy się w spanach, a nie w dawnych jednostkach wydajności. Przed wyborem próbkowania sprawdź aktualne limity planu: limit błędów nie jest budżetem na wszystkie sygnały wysyłane przez SDK.

Nasze ustawienia:

  • tracesSampleRate: 0 w backendzie i frontendzie. Śledzenie rozproszone jest naprawdę przydatne, ale przy 10 tys. jednostek wydajności miesięcznie jedno złe popołudnie mogłoby wyczerpać limit. Możemy włączyć je z niską częstotliwością próbkowania, gdy trzeba zbadać konkretny problem.
  • profilesSampleRate: 0 w backendzie. Z tego samego powodu.
  • Session Replay wyłączone na frontendzie. Kod integracji pozostał, ale obie częstotliwości próbkowania ustawiliśmy na zero. Jeśli do diagnozy krytycznego błędu potrzebny będzie zapis sesji, możemy na jeden dzień ustawić replaysOnErrorSampleRate na 0.05, a potem ponownie go wyłączyć.
  • Filtry before_send w obu środowiskach odrzucają znane, nieistotne zdarzenia.

Zmiany backendu ograniczyły szum związany z błędami wymagającymi działania, a konfigurację przeglądarkowego SDK przygotowano do aktywacji. To różne etapy: sam kod i ustawienia próbkowania nie dowodzą, że zdarzenia z przeglądarki trafiają do właściwego projektu.

Co zmienia się na rynku obserwowalności

Skonfigurowaliśmy bezpłatny plan, ponieważ jest wyjątkowo hojny jak na usługę hostowaną. Warto jednak rozumieć szerszy obraz, bo ekonomia monitoringu się zmienia.

W ciągu ostatnich dwunastu do osiemnastu miesięcy zaszło kilka zmian:

  • Otwarte standardy ograniczają nakład pracy przy migracji, ale nie eliminują go. Instrumentacja zgodna z OTLP może zmniejszyć zależność od zaplecza monitoringu. Przy zmianie nadal trzeba zaplanować i przetestować zapytania specyficzne dla dostawcy, pulpity, reguły alertów i funkcje SDK.
  • Samodzielny hosting zmienia rachunek kosztów. Rozwiązania takie jak GlitchTip i stosy oparte na OTLP są alternatywną drogą monitoringu. Porównaj przechowywanie, kopie zapasowe, aktualizacje i czas pracy inżynierów z usługą hostowaną, a nie tylko koszt maszyny wirtualnej z ceną subskrypcji.
  • Debugowanie wspierane przez AI rozszerza proces. Seer od Sentry proponuje przyczyny źródłowe i poprawki, a autoryzowana integracja MCP może przekazać kontekst błędu do asystenta programistycznego. Proponowaną poprawkę nadal trzeba odtworzyć i objąć testami regresji przed wydaniem.
  • Limity planu wymagają takiej samej uwagi jak funkcje. Liczba błędów, okres przechowywania, próbkowanie i dostęp zespołu wpływają na rachunek. Zacznij od potrzebnych sygnałów i zmierzonego budżetu zdarzeń, a potem porównaj plany z tym obciążeniem.

W chwili opisywanego stanu wydania Sentry pokrywał nasze bieżące potrzeby w zakresie monitorowania błędów. Otwarte interfejsy dają zespołowi więcej możliwości na przyszłość, ale zmiana dostawcy nadal wymagałaby sprawdzenia routingu projektów, alertów, zachowanych danych i funkcji specyficznych dla danego dostawcy.

Kontrole wdrożenia domykają konfigurację monitoringu

W migawce z 17 maja 2026 roku pozostały dwa zadania wdrożeniowe:

  1. Utworzyć osobny projekt Sentry dla Pythona, aby błędy backendu przestały trafiać do javascript-nextjs. DSN należy podmienić w tym samym wpisie Secret Manager, który już odczytuje backend.
  2. Dodać DSN frontendu do ustawień projektu Vercel, aby zaczęły napływać błędy po stronie klienta. Kod już istnieje i inicjuje się warunkowo — brakuje tylko zmiennej środowiskowej.

Przy każdym uruchomieniu monitoringu wyślij kontrolowane zdarzenie testowe z każdego środowiska i sprawdź projekt, środowisko, grupowanie oraz kontekst, zanim uznasz integrację za kompletną. Osobne projekty i zmienna środowiskowa to kroki konfiguracji, a nie dowód dostarczenia zdarzeń.

Dlaczego to ważne

Gdy nie widać, co się psuje, można nadmiernie inwestować w defensywny kod albo zainwestować za mało i wypuścić błędy. Oba podejścia są kosztowne. Niedroga i niezawodna obserwowalność pozwala małemu zespołowi działać jak większemu: wykrywać regresje, zanim zauważą je klienci, naprawiać je bez zgadywania i przeznaczać czas inżynierów na rozwój.

Najważniejsza lekcja: sprawdzaj obie strony — poprawki w aplikacji oraz ścieżkę monitoringu, która powinna ujawnić następną regresję.


← Wróć do bloga