import * as Sentry from "@sentry/nextjs"; import type { CaptureContext, SeverityLevel } from "@sentry/nextjs"; export type RemoteLogLevel = "warn" | "error" | "fatal"; export interface SentryLogPayload { level: RemoteLogLevel; component: string; message: string; data: unknown[]; formatValue: (value: unknown) => string; } export function reportSentryLog(payload: SentryLogPayload): void { try { const error = findError(payload.data); const captureContext = toSentryCaptureContext(payload); if (error) { Sentry.captureException(error, captureContext); return; } Sentry.captureMessage( payload.message || `[${payload.component}] ${payload.level.toUpperCase()} log`, captureContext, ); } catch { // Logging must never break the app runtime. } } function toSentryCaptureContext({ level, component, message, data, formatValue, }: SentryLogPayload): CaptureContext { return { level: toSentrySeverityLevel(level), tags: { component, log_level: level, }, extra: { component, message, data: data.map((item) => formatValue(item)), }, }; } function toSentrySeverityLevel(level: RemoteLogLevel): SeverityLevel { return level === "warn" ? "warning" : level; } function findError(args: unknown[]): Error | null { return args.find((arg): arg is Error => arg instanceof Error) ?? null; }