Sentry, czyli błąd z produkcji razem z kontekstem
Dziennik na serwerze mówi, że coś się wywaliło. Sentry mówi, co się wywaliło, u ilu użytkowników, od którego wdrożenia, w której linii i co użytkownik robił chwilę wcześniej.
Ta różnica decyduje o tym, czy naprawa zajmuje dziesięć minut czy pół dnia. Zamiast odtwarzać problem z opisu zgłoszonego przez klienta, dostajesz ślad stosu, wartości zmiennych, przeglądarkę, wersję aplikacji i ciąg zdarzeń prowadzący do awarii.
Narzędzie obejmuje dziś trzy warstwy: błędy, śledzenie wolnych operacji oraz nagrania sesji. Wszystkie trzy są rozliczane osobno i to jest pierwsza rzecz, którą warto zrozumieć, bo od niej zależy rachunek.
Jednostki rozliczeniowe
Plany opisują nie liczbę osób, tylko liczbę zdarzeń poszczególnych rodzajów, a każdy rodzaj rośnie inaczej.
Błąd to pojedyncze zdarzenie wysłane po awarii. Liczy się każde wystąpienie, a nie każdy rodzaj błędu, więc jedna wadliwa pętla u tysiąca użytkowników to tysiąc zdarzeń, mimo że problem jest jeden.
Fragment śledzenia opisuje jedną operację w obrębie żądania: zapytanie do bazy, wywołanie API, renderowanie komponentu. Jedno żądanie generuje ich kilkadziesiąt, więc ta pozycja rośnie znacznie szybciej niż błędy i przy średnim ruchu bywa największa w całym rachunku.
Nagranie sesji to zapis tego, co widział użytkownik. Kosztuje najwięcej za sztukę i dostarcza najwięcej informacji przy błędach, których nie da się odtworzyć.
Dochodzą do tego dzienniki oraz miary aplikacji, rozliczane objętością przesłanych danych.
Plan bezpłatny obejmuje jedną osobę i pulę błędów wystarczającą na projekt poboczny. Plany zespołowe zawierają w cenie po kilkadziesiąt tysięcy błędów, kilka milionów fragmentów śledzenia i pulę nagrań, a powyżej progu płacisz za zużycie. Konkretne stawki zmieniają się w czasie, więc przed policzeniem budżetu sprawdź aktualny cennik.
Warto wiedzieć, że rezerwacja z góry jest tańsza niż rozliczenie za faktyczne zużycie. Przy stabilnym ruchu różnica sięga kilkunastu procent, a rezerwację da się korygować co miesiąc.
Jak nie przepłacać
Rachunek za to narzędzie rośnie w sposób, który zaskakuje, więc trzy mechanizmy warto uruchomić od pierwszego dnia.
Pierwszy to próbkowanie śledzenia. Wysyłanie wszystkich żądań rzadko ma sens, bo do diagnozy wolnej strony wystarcza kilka procent ruchu. Ustawienie próbkowania na kilkanaście procent zbija tę pozycję wielokrotnie, przy zachowaniu obrazu tego, co jest wolne.
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
replaysSessionSampleRate: 0.01,
})Zwróć uwagę na dwa ustawienia nagrań. Nagrywanie każdej sesji jest kosztowne i zbędne, bo obejrzysz kilkanaście. Nagrywanie jednego procenta sesji zwykłych i wszystkich zakończonych błędem daje ten sam wgląd za ułamek ceny.
Drugi mechanizm to odfiltrowanie szumu przed wysłaniem. Rozszerzenia przeglądarki, boty i błędy sieci u użytkownika generują zdarzenia, których i tak nie naprawisz, a które liczą się do limitu.
beforeSend(event, hint) {
const blad = hint.originalException
if (blad instanceof Error && blad.message.includes('ResizeObserver')) {
return null
}
return event
}Trzeci to zabezpieczenie przed nagłym skokiem i limit wydatków. Wdrożenie z błędem w pętli potrafi wygenerować miesięczny limit w godzinę, a mechanizm wykrywający nagły wzrost zatrzymuje przyjmowanie zdarzeń, zanim to się stanie.
Czwarta rzecz, prostsza od wszystkich powyższych: przejrzyj listę najczęstszych zdarzeń raz w miesiącu. Zwykle okazuje się, że jedna trzecia limitu idzie na dwa albo trzy problemy, które da się naprawić albo odfiltrować w kwadrans.
Mapy źródeł i wersje
To jest część, której pominięcie sprawia, że całe narzędzie przestaje mieć sens, a mimo to zdarza się regularnie.
Kod wysyłany do przeglądarki jest zminimalizowany, więc ślad stosu bez map źródeł wskazuje na linię trzecią pliku o losowej nazwie. Mapy źródeł tłumaczą to z powrotem na Twój kod, razem z nazwami funkcji i numerami linii.
Mapy trzeba wgrać przy budowaniu, a nie udostępniać publicznie. Publiczne mapy oznaczają, że każdy może odtworzyć Twój kod źródłowy, więc wtyczki do narzędzi budujących wysyłają je wprost do usługi i usuwają z paczki.
import { withSentryConfig } from '@sentry/nextjs'
export default withSentryConfig(konfiguracja, {
org: 'moja-firma',
project: 'sklep',
authToken: process.env.SENTRY_AUTH_TOKEN,
sourcemaps: { deleteSourcemapsAfterUpload: true },
silent: !process.env.CI
})Ostatnia opcja w bloku map źródeł jest tu najważniejsza: mapy trafiają do usługi, a potem znikają z katalogu wynikowego, więc nie wyjadą na serwer razem z aplikacją.
W monorepozytorium z pamięcią podręczną budowania warto sprawdzić jeszcze jedną rzecz, bo psuje się cicho. Turborepo przy niezmienionym wejściu odtwarza wynik zadania z pamięci zamiast uruchamiać polecenie, a wysyłka map jest efektem ubocznym tego polecenia, więc przy trafieniu w pamięć podręczną po prostu nie następuje. Wydanie idzie na produkcję bez map, a przyczyna jest niewidoczna w dzienniku, bo budowanie zakończyło się powodzeniem. Rozwiązania są dwa: dołożyć identyfikator wersji do wejść zadania, żeby każde wydanie liczyło się od nowa, albo wynieść wysyłkę do osobnego kroku poza zadaniem objętym pamięcią podręczną.
Drugą rzeczą jest oznaczanie wersji. Bez niego wiesz, że błąd występuje, a z nim wiesz, że pojawił się przy wdrożeniu z wtorku i nie występował wcześniej. To zwykle skraca poszukiwanie przyczyny z godzin do minut, bo zamiast czytać cały moduł, czytasz jeden zestaw zmian.
Powiązanie wersji ze zmianami w repozytorium daje jeszcze jedną rzecz: wskazanie prawdopodobnego autora zmiany, która wprowadziła problem. To nie jest narzędzie do rozliczania ludzi, tylko do szybkiego znalezienia osoby, która wie, co się w tym kodzie działo.
export SENTRY_RELEASE=$(git rev-parse --short HEAD)
npx sentry-cli releases new "$SENTRY_RELEASE"
npx sentry-cli releases set-commits "$SENTRY_RELEASE" --auto
npx sentry-cli releases finalize "$SENTRY_RELEASE"Skrót skrótu zmiany jako numer wersji wystarcza i ma tę zaletę, że nie wymaga niczyjej decyzji. Ważne jest tylko, żeby ta sama wartość trafiła do konfiguracji aplikacji, bo inaczej zgłoszenia przypiszą się do wersji, której nikt nie wdrożył.
Wdrożenie po stronie klienta i serwera
Konfiguracja różni się między warstwami, a przy aplikacjach renderowanych na serwerze trzeba obsłużyć obie.
Po stronie przeglądarki narzędzie przechwytuje nieobsłużone wyjątki, odrzucone obietnice i błędy zasobów. Warto od razu ustawić, które adresy mają być śledzone przy zapytaniach sieciowych.
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
release: process.env.NEXT_PUBLIC_SENTRY_RELEASE,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
replaysSessionSampleRate: 0,
tracePropagationTargets: [/^https:\/\/api\.mojafirma\.pl/]
})Ostatnia opcja rozwiązuje problem, który przy domyślnych ustawieniach objawia się jako nagle odrzucane żądania: nagłówki śledzenia trafiają wszędzie, także do cudzych usług, a te odrzucają je przez zasady dostępu między domenami. Dwie opcje powyżej dotyczą nagrywania sesji i są ustawione tak, żeby nagranie powstawało wyłącznie przy błędzie, a nie przy każdej wizycie.
Po stronie serwera przechwytywane są wyjątki z obsługi żądań, a przy Next.js dochodzi jeszcze warstwa krawędziowa, wymagająca osobnego pliku konfiguracyjnego. Trzy pliki zamiast jednego to jedna z tych rzeczy, które wyglądają na komplikację i wynikają z tego, że kod wykonuje się w trzech różnych środowiskach.
Kontekst użytkownika warto ustawić po zalogowaniu, bo bez niego wiesz, ile było wystąpień, a nie ilu osób dotyczyły. Wystarczy identyfikator, bez adresu pocztowego i danych osobowych, jeśli polityka tego wymaga.
Sentry.setUser({ id: uzytkownik.id })
Sentry.setTag('plan', uzytkownik.plan)Znaczniki warto dobierać ostrożnie. Kilka wartości o niewielkiej liczbie wariantów, na przykład plan albo region, pozwala filtrować listę problemów w sensowny sposób. Znacznik przyjmujący tysiące różnych wartości nie daje nic poza zaśmieceniem interfejsu.
Przy wdrożeniu na platformach takich jak Vercel warto podpiąć powiadomienie o zakończonym wdrożeniu, żeby wersje w narzędziu odpowiadały rzeczywistym wydaniom bez ręcznej pracy.
Sentry kontra alternatywy
| Rozwiązanie | Mocna strona | Słabość | Kiedy wybrać |
|---|---|---|---|
| Sentry | Głęboka diagnostyka błędów, kontekst wykonania | Rachunek rośnie z ruchem, wiele jednostek | Zespół naprawiający błędy w produkcji |
| PostHog | Analityka produktu, nagrania, eksperymenty | Diagnostyka błędów płytsza | Nacisk na zachowanie użytkowników |
| Dzienniki u dostawcy chmury | Wszystko w jednym miejscu, tani start | Brak grupowania i kontekstu błędu | Zaplecze bez interfejsu użytkownika |
| Wdrożenie u siebie | Dane nie wychodzą, brak opłat za zdarzenia | Utrzymanie klastra po Twojej stronie | Wymogi dotyczące miejsca przechowywania |
Pierwszy wiersz wygrywa tam, gdzie liczy się czas od zgłoszenia do naprawy. Grupowanie identycznych błędów w jeden problem, liczba dotkniętych użytkowników i kontekst wykonania to rzeczy, których zwykłe dzienniki nie dają, a które decydują o tym, co naprawiać najpierw.
Ostatni wiersz warto rozważyć uczciwie. Projekt jest otwarty i da się go uruchomić u siebie, natomiast obsługa dużego wolumenu zdarzeń wymaga sporej infrastruktury, więc przy poważnym ruchu bywa droższa niż usługa. To wybór podyktowany zwykle wymogami prawnymi, a nie oszczędnością.
Co robić z tym, co zobaczysz
Narzędzie pokazujące pięćset problemów jest tak samo bezużyteczne jak brak narzędzia, więc warto mieć sposób pracy z tą listą.
Sortuj po liczbie dotkniętych użytkowników, a nie po liczbie wystąpień. Błąd występujący dziesięć tysięcy razy u jednego użytkownika to problem mniejszy niż błąd występujący sto razy u stu osób, a pierwsze sortowanie stawia go na szczycie.
Ustal, co jest błędem, a co szumem. Przerwane żądanie przy zamknięciu karty, wyjątek z rozszerzenia przeglądarki i błąd sieci u użytkownika mobilnego to zdarzenia, których nie naprawisz. Odfiltruj je, zamiast przewijać za każdym razem.
Przypisuj problemy do osób i zamykaj je świadomie. Lista, w której nikt nic nie zamyka, po kwartale przestaje być czytana, a wtedy narzędzie przestaje cokolwiek dawać.
Ustaw powiadomienia wąsko. Wiadomość przy każdym nowym rodzaju błędu jest do przyjęcia, wiadomość przy każdym wystąpieniu nie. Kanał, na który przychodzi czterysta powiadomień dziennie, jest wyciszany po tygodniu i już nikt nie zauważa tego jednego ważnego.
Warto też korzystać z oznaczania problemów jako rozwiązanych w danej wersji. Powrót błędu po trzech miesiącach zostaje wtedy zgłoszony jako nawrót, a nie jako nowy problem, i od razu wiadomo, że poprzednia poprawka czegoś nie objęła.
Dane wrażliwe w zgłoszeniach
Ta część bywa pomijana, a dotyczy danych osobowych trafiających poza Twoją infrastrukturę bez niczyjej decyzji.
Zgłoszenie błędu niesie ze sobą kontekst, a kontekst bywa bogatszy, niż się zakłada. Treść żądania, nagłówki, wartości zmiennych w miejscu awarii i adres strony razem z parametrami. Formularz rejestracji, który się wywalił, potrafi przesłać hasło wpisane przez użytkownika, bo było zmienną w zasięgu funkcji.
Narzędzie usuwa część takich wartości automatycznie, rozpoznając typowe nazwy pól, i to nie wystarcza. Nazwa pola specyficzna dla Twojej aplikacji nie zostanie rozpoznana, więc listę do usunięcia warto rozszerzyć samodzielnie.
Nagrania sesji wymagają osobnej uwagi, bo rejestrują to, co widzi użytkownik. Maskowanie pól formularzy jest ustawieniem domyślnym i warto je zostawić, a przy polach z danymi szczególnie wrażliwymi dołożyć jawne wykluczenia całych obszarów strony.
Adresy stron również niosą dane, jeśli identyfikatory w ścieżce da się powiązać z osobą. To rzadko jest problemem samo w sobie i staje się nim w zestawieniu z resztą kontekstu.
Praktyczna rada: zanim włączysz to na produkcji, wywołaj celowo błąd na stronie z formularzem i przeczytaj, co dokładnie przyszło do interfejsu. Dziesięć minut tej pracy odpowiada na pytanie, na które dokumentacja odpowiada ogólnie.
Typowe błędy
Pierwszy to wysyłanie wszystkich żądań do śledzenia. Kilkanaście procent ruchu wystarcza do diagnozy, a różnica w rachunku jest wielokrotna.
Drugi to nagrywanie każdej sesji. Nagrania sesji zakończonych błędem plus mały procent pozostałych dają ten sam wgląd znacznie taniej.
Trzeci to brak map źródeł. Ślad stosu wskazujący na zminimalizowany kod nie mówi nic, a wgranie map przy budowaniu to jedna wtyczka.
Czwarty to pominięcie oznaczania wersji. Bez niego nie wiesz, przy którym wdrożeniu pojawił się problem, a to jest zwykle najszybsza droga do przyczyny.
Piąty to powiadomienia o każdym pojedynczym wystąpieniu. Kanał zalany powiadomieniami jest wyciszany po tygodniu, a wtedy nie zauważysz tego jednego ważnego.
Szósty to brak zabezpieczenia przed nagłym skokiem. Wdrożenie z błędem w pętli potrafi wyczerpać miesięczny limit w godzinę, a zdarzenia z reszty miesiąca przepadają.
Siódmy to wysyłanie zgłoszeń bez sprawdzenia, co dokładnie w nich jest. Kontekst awarii bywa bogatszy, niż się zakłada, i potrafi zawierać dane, które nie powinny opuścić Twojej infrastruktury.
FAQ
Ile kosztuje Sentry?
Plan bezpłatny obejmuje jedną osobę i pulę błędów wystarczającą na projekt poboczny. Plany zespołowe zawierają w cenie określone pule błędów, fragmentów śledzenia i nagrań, a powyżej progu płacisz za zużycie. Rezerwacja z góry jest tańsza niż rozliczenie bieżące, a stawki warto sprawdzić w aktualnym cenniku.
Dlaczego rachunek rośnie szybciej niż ruch?
Bo jedno żądanie generuje kilkadziesiąt fragmentów śledzenia, a nie jedno zdarzenie. Ta pozycja rośnie najszybciej i przy średnim ruchu bywa największa, więc próbkowanie na poziomie kilkunastu procent jest tu najważniejszym ustawieniem.
Po co są mapy źródeł?
Kod wysyłany do przeglądarki jest zminimalizowany, więc bez map ślad stosu wskazuje na nieczytelny plik. Mapy tłumaczą go z powrotem na Twój kod z nazwami funkcji i numerami linii. Wgrywaj je przy budowaniu i nie udostępniaj publicznie.
Czy to zastąpi analitykę produktu?
Nie. Sentry odpowiada na pytanie, co się psuje i u kogo, a narzędzia takie jak PostHog odpowiadają na pytanie, co użytkownicy robią i gdzie rezygnują. Typowy zespół używa obu, każdego do czego innego.
Czy da się uruchomić to u siebie?
Tak, projekt jest otwarty. Obsługa dużego wolumenu zdarzeń wymaga natomiast sporej infrastruktury, więc przy poważnym ruchu wdrożenie własne bywa droższe niż usługa. To wybór podyktowany zwykle wymogami dotyczącymi miejsca przechowywania danych.
Dokumentacja stoi na stronie projektu, a zarządzanie limitami opisuje osobny dział.