import * as Sentry from '@sentry/node'; import dotenv from 'dotenv'; import path from 'path'; // Sentry se musí inicializovat před načtením ostatních modulů (auto-instrumentace), // proto si tento soubor načítá .env sám — index.ts na to dojde až po importech. dotenv.config({ path: path.resolve(__dirname, `../.env.${process.env.NODE_ENV ?? 'production'}`) }); /** Klíče, jejichž hodnoty se před odesláním do Sentry redigují (hlavičky, tokeny, API klíče…). */ const SENSITIVE_KEY = /authorization|cookie|token|secret|passw|api_?key|(^|[-_])key$/i; /** Tokeny/klíče schované uvnitř řetězců (query parametry, serializovaná JSON body). */ const SENSITIVE_STRING = /((?:token|key|secret|password)"?\s*[=:]\s*"?)[^&\s"',}]+/gi; /** * Rekurzivně rediguje citlivé hodnoty v datech eventu. Console eventy nesou celé * argumenty console.error — u axios chyb tedy i config s hlavičkami a request body * (Bolt token, Gotify/NTFY klíče), které nesmí odejít do Sentry. */ export function scrubEventData(value: unknown, depth = 0): unknown { if (depth > 8) return '[max depth]'; if (typeof value === 'string') return value.replace(SENSITIVE_STRING, '$1[redacted]'); if (Array.isArray(value)) return value.map(v => scrubEventData(v, depth + 1)); if (value && typeof value === 'object') { const out: Record = {}; for (const [k, v] of Object.entries(value)) { out[k] = SENSITIVE_KEY.test(k) ? '[redacted]' : scrubEventData(v, depth + 1); } return out; } return value; } // Bez SENTRY_DSN (dev, Jest, E2E) zůstává Sentry úplně vypnuté. if (process.env.SENTRY_DSN) { Sentry.init({ dsn: process.env.SENTRY_DSN, environment: process.env.NODE_ENV ?? 'production', // Interní logy SDK do konzole — pro ladění, když eventy nedorazí do Sentry debug: process.env.SENTRY_DEBUG === 'true', // Naše self-hosted instance má jen error monitoring (bez Sentry Logs): // console.error/warn se hlásí jako eventy, console.log (např. přechody stavů // Bolt trackingu) se k chybám přikládá jako breadcrumbs (výchozí integrace). integrations: [Sentry.captureConsoleIntegration({ levels: ['error', 'warn'] })], beforeSend(event) { if (event.extra) event.extra = scrubEventData(event.extra) as typeof event.extra; if (event.breadcrumbs) event.breadcrumbs = scrubEventData(event.breadcrumbs) as typeof event.breadcrumbs; if (event.contexts) event.contexts = scrubEventData(event.contexts) as typeof event.contexts; if (event.request) event.request = scrubEventData(event.request) as typeof event.request; if (event.exception) event.exception = scrubEventData(event.exception) as typeof event.exception; return event; }, }); console.log('Sentry: inicializováno'); }