{"version":3,"file":"onuncaughtexception.js","sources":["../../../src/integrations/onuncaughtexception.ts"],"sourcesContent":["import { captureException, convertIntegrationFnToClass, defineIntegration } from '@sentry/core';\nimport { getClient } from '@sentry/core';\nimport type { Integration, IntegrationClass, IntegrationFn } from '@sentry/types';\nimport { logger } from '@sentry/utils';\n\nimport type { NodeClient } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { logAndExitProcess } from './utils/errorhandling';\n\ntype OnFatalErrorHandler = (firstError: Error, secondError?: Error) => void;\n\ntype TaggedListener = NodeJS.UncaughtExceptionListener & {\n tag?: string;\n};\n\n// CAREFUL: Please think twice before updating the way _options looks because the Next.js SDK depends on it in `index.server.ts`\ninterface OnUncaughtExceptionOptions {\n // TODO(v8): Evaluate whether we should switch the default behaviour here.\n // Also, we can evaluate using https://nodejs.org/api/process.html#event-uncaughtexceptionmonitor per default, and\n // falling back to current behaviour when that's not available.\n /**\n * Controls if the SDK should register a handler to exit the process on uncaught errors:\n * - `true`: The SDK will exit the process on all uncaught errors.\n * - `false`: The SDK will only exit the process when there are no other `uncaughtException` handlers attached.\n *\n * Default: `true`\n */\n exitEvenIfOtherHandlersAreRegistered: boolean;\n\n /**\n * This is called when an uncaught error would cause the process to exit.\n *\n * @param firstError Uncaught error causing the process to exit\n * @param secondError Will be set if the handler was called multiple times. This can happen either because\n * `onFatalError` itself threw, or because an independent error happened somewhere else while `onFatalError`\n * was running.\n */\n onFatalError?(this: void, firstError: Error, secondError?: Error): void;\n}\n\nconst INTEGRATION_NAME = 'OnUncaughtException';\n\nconst _onUncaughtExceptionIntegration = ((options: Partial = {}) => {\n const _options = {\n exitEvenIfOtherHandlersAreRegistered: true,\n ...options,\n };\n\n return {\n name: INTEGRATION_NAME,\n // TODO v8: Remove this\n setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function\n setup(client: NodeClient) {\n global.process.on('uncaughtException', makeErrorHandler(client, _options));\n },\n };\n}) satisfies IntegrationFn;\n\nexport const onUncaughtExceptionIntegration = defineIntegration(_onUncaughtExceptionIntegration);\n\n/**\n * Global Exception handler.\n * @deprecated Use `onUncaughtExceptionIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const OnUncaughtException = convertIntegrationFnToClass(\n INTEGRATION_NAME,\n onUncaughtExceptionIntegration,\n) as IntegrationClass void }> & {\n new (\n options?: Partial<{\n exitEvenIfOtherHandlersAreRegistered: boolean;\n onFatalError?(this: void, firstError: Error, secondError?: Error): void;\n }>,\n ): Integration;\n};\n\n// eslint-disable-next-line deprecation/deprecation\nexport type OnUncaughtException = typeof OnUncaughtException;\n\ntype ErrorHandler = { _errorHandler: boolean } & ((error: Error) => void);\n\n/** Exported only for tests */\nexport function makeErrorHandler(client: NodeClient, options: OnUncaughtExceptionOptions): ErrorHandler {\n const timeout = 2000;\n let caughtFirstError: boolean = false;\n let caughtSecondError: boolean = false;\n let calledFatalError: boolean = false;\n let firstError: Error;\n\n const clientOptions = client.getOptions();\n\n return Object.assign(\n (error: Error): void => {\n let onFatalError: OnFatalErrorHandler = logAndExitProcess;\n\n if (options.onFatalError) {\n onFatalError = options.onFatalError;\n } else if (clientOptions.onFatalError) {\n onFatalError = clientOptions.onFatalError as OnFatalErrorHandler;\n }\n\n // Attaching a listener to `uncaughtException` will prevent the node process from exiting. We generally do not\n // want to alter this behaviour so we check for other listeners that users may have attached themselves and adjust\n // exit behaviour of the SDK accordingly:\n // - If other listeners are attached, do not exit.\n // - If the only listener attached is ours, exit.\n const userProvidedListenersCount = (\n global.process.listeners('uncaughtException') as TaggedListener[]\n ).reduce((acc, listener) => {\n if (\n // There are 3 listeners we ignore:\n listener.name === 'domainUncaughtExceptionClear' || // as soon as we're using domains this listener is attached by node itself\n (listener.tag && listener.tag === 'sentry_tracingErrorCallback') || // the handler we register for tracing\n (listener as ErrorHandler)._errorHandler // the handler we register in this integration\n ) {\n return acc;\n } else {\n return acc + 1;\n }\n }, 0);\n\n const processWouldExit = userProvidedListenersCount === 0;\n const shouldApplyFatalHandlingLogic = options.exitEvenIfOtherHandlersAreRegistered || processWouldExit;\n\n if (!caughtFirstError) {\n // this is the first uncaught error and the ultimate reason for shutting down\n // we want to do absolutely everything possible to ensure it gets captured\n // also we want to make sure we don't go recursion crazy if more errors happen after this one\n firstError = error;\n caughtFirstError = true;\n\n if (getClient() === client) {\n captureException(error, {\n originalException: error,\n captureContext: {\n level: 'fatal',\n },\n mechanism: {\n handled: false,\n type: 'onuncaughtexception',\n },\n });\n }\n\n if (!calledFatalError && shouldApplyFatalHandlingLogic) {\n calledFatalError = true;\n onFatalError(error);\n }\n } else {\n if (shouldApplyFatalHandlingLogic) {\n if (calledFatalError) {\n // we hit an error *after* calling onFatalError - pretty boned at this point, just shut it down\n DEBUG_BUILD &&\n logger.warn(\n 'uncaught exception after calling fatal error shutdown callback - this is bad! forcing shutdown',\n );\n logAndExitProcess(error);\n } else if (!caughtSecondError) {\n // two cases for how we can hit this branch:\n // - capturing of first error blew up and we just caught the exception from that\n // - quit trying to capture, proceed with shutdown\n // - a second independent error happened while waiting for first error to capture\n // - want to avoid causing premature shutdown before first error capture finishes\n // it's hard to immediately tell case 1 from case 2 without doing some fancy/questionable domain stuff\n // so let's instead just delay a bit before we proceed with our action here\n // in case 1, we just wait a bit unnecessarily but ultimately do the same thing\n // in case 2, the delay hopefully made us wait long enough for the capture to finish\n // two potential nonideal outcomes:\n // nonideal case 1: capturing fails fast, we sit around for a few seconds unnecessarily before proceeding correctly by calling onFatalError\n // nonideal case 2: case 2 happens, 1st error is captured but slowly, timeout completes before capture and we treat second error as the sendErr of (nonexistent) failure from trying to capture first error\n // note that after hitting this branch, we might catch more errors where (caughtSecondError && !calledFatalError)\n // we ignore them - they don't matter to us, we're just waiting for the second error timeout to finish\n caughtSecondError = true;\n setTimeout(() => {\n if (!calledFatalError) {\n // it was probably case 1, let's treat err as the sendErr and call onFatalError\n calledFatalError = true;\n onFatalError(firstError, error);\n } else {\n // it was probably case 2, our first error finished capturing while we waited, cool, do nothing\n }\n }, timeout); // capturing could take at least sendTimeout to fail, plus an arbitrary second for how long it takes to collect surrounding source etc\n }\n }\n }\n },\n { _errorHandler: true },\n );\n}\n"],"names":[],"mappings":"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"}