/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ import * as Sentry from "@sentry/browser" import { Cause, Effect, type LogLevel } from "effect-app" import { CauseException, tryToJson, tryToReport } from "effect-app/client/errors" import { dropUndefined, LogLevelToSentry } from "effect-app/utils" export const tryCauseException = (cause: Cause.Cause, name: string): CauseException => { try { return new CauseException(cause, name) } catch { return new CauseException(Cause.die(new Error("Failed to create CauseException")), name) } } export function reportError(name: string) { return Effect.fnUntraced( function*( cause: Cause.Cause, extras?: Record, level: LogLevel.Severity = "Error" ) { if (Cause.hasInterruptsOnly(cause)) { yield* Effect.logDebug("Interrupted").pipe(Effect.annotateLogs("extras", JSON.stringify(extras ?? {}))) return Cause.squash(cause) } const error = tryCauseException(cause, name) yield* reportSentry(error, extras, LogLevelToSentry(level)) yield* Effect .logWithLevel(level)("Reporting error", cause) .pipe( Effect.annotateLogs(dropUndefined({ extras, error: tryToReport(error), cause: tryToJson(cause), __error_name__: name })), Effect.catchCause((cause) => Effect.logWarning("Failed to log error", cause)), Effect.catchCause(() => Effect.logFatal("Failed to log error cause")) ) return error }, (effect) => Effect.tapCause(effect, (cause) => Effect.logError("Failed to report error", cause).pipe( Effect.tapCause(() => Effect.logFatal("Failed to log error cause")) )) ) } function reportSentry( error: CauseException, extras: Record | undefined, level: Sentry.SeverityLevel = "error" ) { return Effect.sync(() => { const scope = new Sentry.Scope() scope.setLevel(level) if (extras) scope.setContext("extras", extras) scope.setContext("error", tryToReport(error) as any) scope.setContext("cause", tryToJson(error.originalCause) as any) Sentry.captureException(error, scope) }) } export function logError(name: string) { return Effect.fnUntraced( function*(cause: Cause.Cause, extras?: Record) { if (Cause.hasInterruptsOnly(cause)) { yield* Effect.logDebug("Interrupted").pipe(Effect.annotateLogs(dropUndefined({ extras }))) return } yield* Effect .logWarning("Logging error", cause) .pipe(Effect.annotateLogs(dropUndefined({ extras, cause: tryToJson(cause), __error_name__: name }))) }, (effect) => Effect.tapCause(effect, (cause) => Effect.logError("Failed to log error", cause).pipe( Effect.tapCause(() => Effect.logFatal("Failed to log error cause")) )) ) } export function captureException(error: unknown, extras?: Record) { const scope = new Sentry.Scope() if (extras) scope.setContext("extras", extras) Sentry.captureException(error, extras) console.error(error, extras) } export const reportMessage = Effect.fnUntraced(function*(message: string, extras?: Record) { const scope = new Sentry.Scope() if (extras) scope.setContext("extras", extras) Sentry.captureMessage(message, scope) console.warn(message, extras) })