| import { logger } from '../logger'; |
| import * as Sentry from '@sentry/node'; |
|
|
| export interface ErrorContext { |
| organizationId?: string; |
| userId?: string; |
| jobId?: string; |
| jobName?: string; |
| extra?: Record<string, unknown>; |
| } |
|
|
| let sentryInitialized = false; |
|
|
| export function initSentry() { |
| const dsn = process.env.SENTRY_DSN; |
| if (!dsn) { |
| logger.info('[SENTRY] SENTRY_DSN not set — error reporting via logger only'); |
| return; |
| } |
| Sentry.init({ |
| dsn, |
| environment: process.env.NODE_ENV || 'production', |
| tracesSampleRate: 0.1, |
| }); |
| sentryInitialized = true; |
| logger.info('[SENTRY] Initialized'); |
| } |
|
|
| export const reportError = (error: unknown, context: ErrorContext) => { |
| const errorMessage = error instanceof Error ? error.message : String(error); |
| const errorStack = error instanceof Error ? error.stack : undefined; |
|
|
| logger.error({ |
| msg: `[ERROR-REPORT] ${context.jobName || 'unknown'}: ${errorMessage}`, |
| context: { ...context, stack: errorStack } |
| }); |
|
|
| if (sentryInitialized) { |
| Sentry.withScope(scope => { |
| scope.setTags({ |
| jobName: context.jobName ?? 'unknown', |
| organizationId: context.organizationId ?? 'unknown', |
| }); |
| if (context.extra) scope.setExtras(context.extra); |
| Sentry.captureException(error); |
| }); |
| } |
| }; |
|
|
| export const withErrorLogging = async <T>( |
| task: () => Promise<T>, |
| context: ErrorContext |
| ): Promise<T | undefined> => { |
| try { |
| return await task(); |
| } catch (error) { |
| reportError(error, context); |
| throw error; |
| } |
| }; |
|
|