Na statku kosmicznym każda awaria jest rejestrowana w czarnej skrzynce. Bez niej zaloga nie mogłaby analizowac przyczyn problemów po fakcie. W aplikacjach React mamy dokladnie ten sam problem -- jeśli błąd wystapi u uzytkownika na produkcji, a my go nie zalogujemy, nigdy sie o nim nie dowiemy. Logowanie i monitoring błędów to Twoja czarna skrzynka produkcyjna.
W srodowisku produkcyjnym potrzebujemy kilku warstw logowania:
console.error jest przydatny podczas pracy lokalnej, ale na produkcji uzytkownik go nie widzi, a Ty nie masz do niego dostepu.1// Dobre do developmentu, bezuzyteczne na produkcji
2componentDidCatch(error, errorInfo) {
3 console.error('Error caught:', error);
4 console.error('Component stack:', errorInfo.componentStack);
5}Na produkcji błędy musza byc wysylane do serwisu monitorujacego:
1class ErrorBoundary extends React.Component {
2 componentDidCatch(error, errorInfo) {
3 // Wyslanie do serwisu monitorujacego
4 logErrorToService({
5 message: error.message,
6 stack: error.stack,
7 componentStack: errorInfo.componentStack,
8 timestamp: new Date().toISOString(),
9 url: window.location.href,
10 userAgent: navigator.userAgent,
11 });
12 }
13
14 // ...render z fallback
15}
16
17async function logErrorToService(errorData) {
18 try {
19 await fetch('/api/errors', {
20 method: 'POST',
21 headers: { 'Content-Type': 'application/json' },
22 body: JSON.stringify(errorData),
23 });
24 } catch (e) {
25 // Fallback -- nie blokuj aplikacji jesli logowanie sie nie powiedzie
26 console.error('Failed to log error:', e);
27 }
28}Sentry to najpopularniejszy serwis do monitorowania błędów w aplikacjach JavaScript i React. Inne popularne narzedzia to LogRocket, Bugsnag, Datadog i New Relic.
1import * as Sentry from '@sentry/react';
2
3// Inicjalizacja w main/index.js
4Sentry.init({
5 dsn: 'https://klucz@sentry.io/projekt',
6 environment: 'production',
7 // Procent sesji do rejestrowania (performance)
8 tracesSampleRate: 0.2,
9});
10
11// Sentry automatycznie przechwytuje:
12// - Nieobsluzone wyjatki (uncaught exceptions)
13// - Nieobsluzone rejection Promise
14// - Bledy sieciowe1import * as Sentry from '@sentry/react';
2
3// Sentry dostarcza gotowy Error Boundary
4function App() {
5 return (
6 <Sentry.ErrorBoundary
7 fallback={({ error }) => (
8 <div className="error-page">
9 <h2>Cos poszlo nie tak</h2>
10 <p>Blad zostal automatycznie zgłoszony</p>
11 <button onClick={() => window.location.reload()}>
12 Odswierz strone
13 </button>
14 </div>
15 )}
16 >
17 <SpaceStation />
18 </Sentry.ErrorBoundary>
19 );
20}Sentry pozwala dodawac kontekst do bledow -- informacje o uzytkowniku, ostatnich akcjach (breadcrumbs) i dodatkowe dane:
1// Ustawienie kontekstu uzytkownika
2Sentry.setUser({
3 id: user.id,
4 email: user.email,
5 username: user.callsign,
6});
7
8// Reczne dodawanie breadcrumbs (slad akcji uzytkownika)
9Sentry.addBreadcrumb({
10 category: 'navigation',
11 message: 'Uzytkownik przeszedl do panelu misji',
12 level: 'info',
13});
14
15// Reczne raportowanie bledu z dodatkowym kontekstem
16Sentry.captureException(error, {
17 extra: {
18 missionId: currentMission.id,
19 moduleState: moduleStatus,
20 },
21});Możesz stworzyc wlasny hook, ktory centralizuje logike logowania:
1function useErrorLogger() {
2 const logError = useCallback((error, context = {}) => {
3 const errorReport = {
4 message: error.message,
5 stack: error.stack,
6 timestamp: new Date().toISOString(),
7 url: window.location.href,
8 ...context,
9 };
10
11 // W produkcji wyslij do serwisu
12 if (process.env.NODE_ENV === 'production') {
13 sendToErrorService(errorReport);
14 }
15
16 // W development loguj do konsoli
17 console.error('[ErrorLogger]', errorReport);
18 }, []);
19
20 return { logError };
21}
22
23// Uzycie w komponencie
24function MissionControl() {
25 const { logError } = useErrorLogger();
26
27 const handleDataFetch = async () => {
28 try {
29 const data = await fetchMissionData();
30 setMissions(data);
31 } catch (error) {
32 logError(error, {
33 component: 'MissionControl',
34 action: 'fetchMissionData',
35 });
36 setError('Nie udalo sie pobrac danych misji');
37 }
38 };
39}Oprócz Error Boundaries i try-catch, warto dodac globalne handlery, ktore przechwycą błędy wymykajace sie innym mechanizmom:
1// Globalne przechwytywanie nieprzechwyconych błędów
2window.addEventListener('error', (event) => {
3 logErrorToService({
4 type: 'uncaught_error',
5 message: event.message,
6 filename: event.filename,
7 lineno: event.lineno,
8 colno: event.colno,
9 });
10});
11
12// Globalne przechwytywanie nieobsluzonych Promise rejections
13window.addEventListener('unhandledrejection', (event) => {
14 logErrorToService({
15 type: 'unhandled_rejection',
16 message: event.reason?.message || 'Unknown rejection',
17 stack: event.reason?.stack,
18 });
19});Nie wszystkie bledy są równie wazne. Serwisy error tracking pozwalaja na klasyfikacje:
1// Krytyczny blad - aplikacja nie dziala
2Sentry.captureException(error, { level: 'fatal' });
3
4// Blad - funkcjonalnosc nie dziala, ale aplikacja tak
5Sentry.captureException(error, { level: 'error' });
6
7// Ostrzezenie - cos moze byc nie tak
8Sentry.captureMessage('API odpowiada wolno', 'warning');
9
10// Informacja - przydatna do debugowania
11Sentry.captureMessage('Uzytkownik zmienil jezyk', 'info');Kod produkcyjny jest zminifikowany -- stack trace jest nieczytelny bez source maps. Source maps to jak mapa dekodujaca -- pozwalaja przetlumaczyc pozycje w zminifikowanym kodzie na oryginalne pliki zrodlowe.
1// Bez source maps stack trace wyglada tak:
2// Error at e.render (main.a1b2c3.js:1:45678)
3
4// Z source maps:
5// Error at MissionControl.render (MissionControl.jsx:42:15)1// webpack.config.js
2module.exports = {
3 devtool: 'source-map', // Generuj source maps
4 // ...
5};
6
7// Wazne: source maps NIE powinny byc publiczne!
8// Uploaduj je do Sentry, ale nie serwuj uzytkownikom:
9// sentry-cli sourcemaps upload ./buildSource maps pozwalaja Ci zobaczyc dokladnie w ktorej linii oryginalnego kodu wystapil blad, nawet jesli produkcyjny bundle jest zminifikowany do jednej linii. To jak posiadanie schematu technicznego statku kosmicznego -- zamiast patrzec na niezrozumialy zminifikowany panel, widzisz dokladnie ktory modul zawiodl i dlaczego. Pamietaj jednak, zeby nigdy nie udostepniac source maps publicznie -- to bylby jak udostepnienie planow statku potencjalnym najezdcom.