Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 24x 24x 24x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 24x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 26x 2x 26x 624x 88x 2x 2x 2x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x | // src/services/sentry.server.ts /** * Sentry SDK initialization for error tracking. * Implements ADR-015: Application Performance Monitoring and Error Tracking. * * This module configures @sentry/node to send errors to our self-hosted * Bugsink instance, which is Sentry-compatible. * * IMPORTANT: This module should be imported and initialized at the very top * of server.ts, before any other imports, to ensure all errors are captured. * * Note: Uses Sentry SDK v8+ API which differs significantly from v7. */ import * as Sentry from '@sentry/node'; import type { Request, Response, NextFunction, ErrorRequestHandler } from 'express'; import { config, isSentryConfigured, isProduction, isTest } from '../config/env'; import { logger } from './logger.server'; /** * Initializes the Sentry SDK with the configured DSN. * Should be called once at application startup. */ export function initSentry(): void { Eif (!isSentryConfigured) { logger.info('[Sentry] Error tracking disabled (SENTRY_DSN not configured)'); return; } // Don't initialize Sentry in test environment if (isTest) { logger.debug('[Sentry] Skipping initialization in test environment'); return; } Sentry.init({ dsn: config.sentry.dsn, environment: config.sentry.environment || config.server.nodeEnv, debug: config.sentry.debug, // Performance monitoring - disabled for now to keep it simple tracesSampleRate: 0, // Before sending an event, add additional context beforeSend(event, hint) { // In development, log errors to console as well if (!isProduction && hint.originalException) { logger.error( { err: hint.originalException, sentryEventId: event.event_id }, '[Sentry] Capturing error', ); } return event; }, }); logger.info( { environment: config.sentry.environment || config.server.nodeEnv }, '[Sentry] Error tracking initialized', ); } /** * Creates Sentry middleware for Express. * Returns the request handler and error handler middleware. * * In Sentry SDK v8+, the old Handlers.requestHandler and Handlers.errorHandler * have been replaced. Request context is now captured automatically via the * Express integration. We provide a custom error handler that filters errors. */ export function getSentryMiddleware(): { requestHandler: (req: Request, res: Response, next: NextFunction) => void; errorHandler: ErrorRequestHandler; } { Eif (!isSentryConfigured || isTest) { // Return no-op middleware when Sentry is not configured return { requestHandler: (_req: Request, _res: Response, next: NextFunction) => next(), errorHandler: (_err: Error, _req: Request, _res: Response, next: NextFunction) => next(_err), }; } return { // In SDK v8+, request context is captured automatically. // This middleware is a placeholder for compatibility. requestHandler: (_req: Request, _res: Response, next: NextFunction) => next(), // Custom error handler that captures errors to Sentry errorHandler: (err: Error, _req: Request, _res: Response, next: NextFunction) => { // Only send 5xx errors to Sentry by default const statusCode = (err as Error & { statusCode?: number }).statusCode || (err as Error & { status?: number }).status || 500; if (statusCode >= 500) { Sentry.captureException(err); } // Pass the error to the next error handler next(err); }, }; } /** * Captures an exception and sends it to Sentry. * Use this for errors that are caught and handled gracefully. */ export function captureException(error: Error, context?: Record<string, unknown>): string | null { Eif (!isSentryConfigured || isTest) { return null; } if (context) { Sentry.setContext('additional', context); } return Sentry.captureException(error); } /** * Captures a message and sends it to Sentry. * Use this for non-exception events that should be tracked. */ export function captureMessage( message: string, level: Sentry.SeverityLevel = 'info', ): string | null { Eif (!isSentryConfigured || isTest) { return null; } return Sentry.captureMessage(message, level); } /** * Sets the user context for all subsequent events. * Call this after user authentication. */ export function setUser(user: { id: string; email?: string; username?: string } | null): void { Eif (!isSentryConfigured || isTest) { return; } Sentry.setUser(user); } /** * Adds a breadcrumb to the current scope. * Breadcrumbs are logged actions that led up to an error. */ export function addBreadcrumb(breadcrumb: Sentry.Breadcrumb): void { Eif (!isSentryConfigured || isTest) { return; } Sentry.addBreadcrumb(breadcrumb); } // Re-export Sentry for advanced usage export { Sentry }; |