/** * FIX #20: Configuration Sentry pour error tracking * - Intégration avec le logger structuré * - Capture automatique des erreurs React * - Enrichissement avec contexte (request_id, user_id, etc.) */ import * as Sentry from '@sentry/react'; import { logger, getLogContext } from '@/utils/logger'; /** * Initialiser Sentry avec configuration */ export function initSentry(): void { const dsn = import.meta.env.VITE_SENTRY_DSN; const environment = import.meta.env.MODE || 'development'; const enabled = import.meta.env.PROD && dsn; // Activer uniquement en production si DSN configuré if (!enabled) { if (environment !== 'development' && !dsn) { logger.debug('[Sentry] Error tracking disabled', { reason: 'DSN not configured', environment, }); } return; } Sentry.init({ dsn, environment, integrations: [ Sentry.browserTracingIntegration(), Sentry.replayIntegration({ maskAllText: true, blockAllMedia: true, }), ], // Performance Monitoring tracesSampleRate: environment === 'production' ? 0.1 : 1.0, // 10% en prod, 100% en dev // Session Replay replaysSessionSampleRate: 0.1, // 10% des sessions replaysOnErrorSampleRate: 1.0, // 100% des sessions avec erreur // Filtrage des erreurs beforeSend(event, hint) { // Enrichir avec le contexte du logger const logContext = getLogContext(); if (logContext.request_id) { event.tags = { ...event.tags, request_id: logContext.request_id }; } if (logContext.user_id) { event.user = { ...event.user, id: String(logContext.user_id) }; } // Logger l'erreur avec le logger structuré const error = hint.originalException; logger.error('[Sentry] Error captured', { error: error instanceof Error ? error.message : String(error), sentry_event_id: event.event_id, ...logContext, }); return event; }, // Ignorer certaines erreurs ignoreErrors: [ // Erreurs réseau courantes 'NetworkError', 'Network request failed', 'Failed to fetch', // Erreurs de résolution DNS 'Resolving timed out', // Erreurs de CORS 'CORS', // Erreurs de script tiers 'Script error', 'Non-Error promise rejection captured', ], // Ignorer certaines URLs denyUrls: [ // Extensions de navigateur /extensions\//i, /^chrome:\/\//i, /^chrome-extension:\/\//i, // Scripts tiers /cdn\./i, ], }); logger.info('[Sentry] Error tracking initialized', { environment, dsn_configured: !!dsn, }); } /** * Enrichir le contexte Sentry avec les informations du logger */ export function setSentryContext(context: Record): void { Sentry.setContext('application', context); } /** * Capturer une exception manuellement */ export function captureException( error: Error, context?: Record, ): string { if (context) { Sentry.setContext('custom', context); } // Enrichir avec le contexte du logger const logContext = getLogContext(); if (logContext.request_id) { Sentry.setTag('request_id', String(logContext.request_id)); } if (logContext.user_id) { Sentry.setUser({ id: String(logContext.user_id) }); } return Sentry.captureException(error); } /** * Capturer un message personnalisé */ export function captureMessage( message: string, level: Sentry.SeverityLevel = 'info', context?: Record, ): string { if (context) { Sentry.setContext('custom', context); } // Enrichir avec le contexte du logger const logContext = getLogContext(); if (logContext.request_id) { Sentry.setTag('request_id', String(logContext.request_id)); } return Sentry.captureMessage(message, level); }