🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@sentry/node-native

Package Overview
Dependencies
Maintainers
1
Versions
94
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sentry/node-native - npm Package Compare versions

Comparing version
10.57.0
to
10.58.0
+1
-1
build/cjs/event-loop-block-integration.js

@@ -6,3 +6,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });

const core = require('@sentry/core');
const nodeNativeStacktrace = require('@sentry-internal/node-native-stacktrace');
const nodeNativeStacktrace = require('@sentry/node-native-stacktrace');
const common = require('./common.js');

@@ -9,0 +9,0 @@

@@ -1,1 +0,1 @@

{"version":3,"file":"event-loop-block-integration.js","sources":["../../src/event-loop-block-integration.ts"],"sourcesContent":["import { isPromise } from 'node:util/types';\nimport { isMainThread, Worker } from 'node:worker_threads';\nimport type {\n ClientOptions,\n Contexts,\n DsnComponents,\n Event,\n EventHint,\n Integration,\n IntegrationFn,\n ScopeData,\n} from '@sentry/core';\nimport {\n debug,\n defineIntegration,\n getClient,\n getCurrentScope,\n getFilenameToDebugIdMap,\n getGlobalScope,\n getIsolationScope,\n mergeScopeData,\n} from '@sentry/core';\nimport type { NodeClient } from '@sentry/node';\nimport { registerThread, threadPoll } from '@sentry-internal/node-native-stacktrace';\nimport type { ThreadBlockedIntegrationOptions, WorkerStartData } from './common';\nimport { POLL_RATIO } from './common';\n\nconst INTEGRATION_NAME = 'ThreadBlocked';\nconst DEFAULT_THRESHOLD_MS = 1_000;\n\nfunction log(message: string, ...args: unknown[]): void {\n debug.log(`[Sentry Event Loop Blocked] ${message}`, ...args);\n}\n\n/**\n * Gets contexts by calling all event processors. This shouldn't be called until all integrations are setup\n */\nasync function getContexts(client: NodeClient): Promise<Contexts> {\n let event: Event | null = { message: INTEGRATION_NAME };\n const eventHint: EventHint = {};\n\n for (const processor of client.getEventProcessors()) {\n if (event === null) break;\n event = await processor(event, eventHint);\n }\n\n return event?.contexts || {};\n}\n\nfunction getLocalScopeData(): ScopeData {\n const globalScope = getGlobalScope().getScopeData();\n const currentScope = getCurrentScope().getScopeData();\n mergeScopeData(globalScope, currentScope);\n return globalScope;\n}\n\ntype IntegrationInternal = { start: () => void; stop: () => void };\n\nfunction poll(enabled: boolean, clientOptions: ClientOptions): void {\n try {\n const currentSession = getIsolationScope().getSession();\n // We need to copy the session object and remove the toJSON method so it can be sent to the worker\n // serialized without making it a SerializedSession\n const session = currentSession ? { ...currentSession, toJSON: undefined } : undefined;\n const scope = getLocalScopeData();\n // message the worker to tell it the main event loop is still running\n threadPoll(enabled, { session, scope, debugImages: getFilenameToDebugIdMap(clientOptions.stackParser) });\n } catch {\n // we ignore all errors\n }\n}\n\n/**\n * Starts polling\n */\nfunction startPolling(\n client: NodeClient,\n integrationOptions: Partial<ThreadBlockedIntegrationOptions>,\n): IntegrationInternal | undefined {\n if (client.asyncLocalStorageLookup) {\n const { asyncLocalStorage, contextSymbol } = client.asyncLocalStorageLookup;\n registerThread({ asyncLocalStorage, stateLookup: ['_currentContext', contextSymbol] });\n } else {\n registerThread();\n }\n\n let enabled = true;\n\n const initOptions = client.getOptions();\n const pollInterval = (integrationOptions.threshold || DEFAULT_THRESHOLD_MS) / POLL_RATIO;\n\n // unref so timer does not block exit\n setInterval(() => poll(enabled, initOptions), pollInterval).unref();\n\n return {\n start: () => {\n enabled = true;\n },\n stop: () => {\n enabled = false;\n // poll immediately because the timer above might not get a chance to run\n // before the event loop gets blocked\n poll(enabled, initOptions);\n },\n };\n}\n\n/**\n * Starts the worker thread that will monitor the other threads.\n *\n * This function is only called in the main thread.\n */\nasync function startWorker(\n dsn: DsnComponents,\n client: NodeClient,\n integrationOptions: Partial<ThreadBlockedIntegrationOptions>,\n): Promise<void> {\n const contexts = await getContexts(client);\n\n // These will not be accurate if sent later from the worker thread\n delete contexts.app?.app_memory;\n delete contexts.device?.free_memory;\n\n const initOptions = client.getOptions();\n\n const sdkMetadata = client.getSdkMetadata() || {};\n if (sdkMetadata.sdk) {\n sdkMetadata.sdk.integrations = initOptions.integrations.map(i => i.name);\n }\n\n const options: WorkerStartData = {\n debug: debug.isEnabled(),\n dsn,\n tunnel: initOptions.tunnel,\n environment: initOptions.environment || 'production',\n release: initOptions.release,\n dist: initOptions.dist,\n sdkMetadata,\n appRootPath: integrationOptions.appRootPath,\n threshold: integrationOptions.threshold || DEFAULT_THRESHOLD_MS,\n maxEventsPerHour: integrationOptions.maxEventsPerHour || 1,\n staticTags: integrationOptions.staticTags || {},\n contexts,\n };\n\n const worker = new Worker(new URL('./event-loop-block-watchdog.js', import.meta.url), {\n workerData: options,\n // We don't want any Node args like --import to be passed to the worker\n execArgv: [],\n env: { ...process.env, NODE_OPTIONS: undefined },\n });\n\n process.on('exit', () => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n });\n\n worker.once('error', (err: Error) => {\n log('watchdog worker error', err);\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n });\n\n worker.once('exit', (code: number) => {\n log('watchdog worker exit', code);\n });\n\n // Ensure this thread can't block app exit\n worker.unref();\n}\n\nconst _eventLoopBlockIntegration = ((options: Partial<ThreadBlockedIntegrationOptions> = {}) => {\n let polling: IntegrationInternal | undefined;\n\n return {\n name: INTEGRATION_NAME,\n async afterAllSetup(client: NodeClient): Promise<void> {\n const dsn = client.getDsn();\n\n if (!dsn) {\n log('No DSN configured, skipping starting integration');\n return;\n }\n\n // Otel is not setup until after afterAllSetup returns.\n setImmediate(async () => {\n try {\n polling = startPolling(client, options);\n\n if (isMainThread) {\n await startWorker(dsn, client, options);\n }\n } catch (err) {\n log('Failed to start integration', err);\n return;\n }\n });\n },\n start() {\n polling?.start();\n },\n stop() {\n polling?.stop();\n },\n } as Integration & IntegrationInternal;\n}) satisfies IntegrationFn;\n\n/**\n * Monitors the Node.js event loop for blocking behavior and reports blocked events to Sentry.\n *\n * Uses a background worker thread to detect when the main thread is blocked for longer than\n * the configured threshold (default: 1 second).\n *\n * When instrumenting via the `--import` flag, this integration will\n * automatically monitor all worker threads as well.\n *\n * ```js\n * // instrument.mjs\n * import * as Sentry from '@sentry/node';\n * import { eventLoopBlockIntegration } from '@sentry/node-native';\n *\n * Sentry.init({\n * dsn: '__YOUR_DSN__',\n * integrations: [\n * eventLoopBlockIntegration({\n * threshold: 500, // Report blocks longer than 500ms\n * }),\n * ],\n * });\n * ```\n *\n * Start your application with:\n * ```bash\n * node --import instrument.mjs app.mjs\n * ```\n */\nexport const eventLoopBlockIntegration = defineIntegration(_eventLoopBlockIntegration);\n\nexport function disableBlockDetectionForCallback<T>(callback: () => T): T;\nexport function disableBlockDetectionForCallback<T>(callback: () => Promise<T>): Promise<T>;\n/**\n * Disables Event Loop Block detection for the current thread for the duration\n * of the callback.\n *\n * This utility function allows you to disable block detection during operations that\n * are expected to block the event loop, such as intensive computational tasks or\n * synchronous I/O operations.\n */\nexport function disableBlockDetectionForCallback<T>(callback: () => T | Promise<T>): T | Promise<T> {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return callback();\n }\n\n integration.stop();\n\n try {\n const result = callback();\n if (isPromise(result)) {\n return result.finally(() => integration.start());\n }\n\n integration.start();\n return result;\n } catch (error) {\n integration.start();\n throw error;\n }\n}\n\n/**\n * Pauses the block detection integration.\n *\n * This function pauses event loop block detection for the current thread.\n */\nexport function pauseEventLoopBlockDetection(): void {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return;\n }\n\n integration.stop();\n}\n\n/**\n * Restarts the block detection integration.\n *\n * This function restarts event loop block detection for the current thread.\n */\nexport function restartEventLoopBlockDetection(): void {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return;\n }\n\n integration.start();\n}\n"],"names":["debug","getGlobalScope","getCurrentScope","mergeScopeData","getIsolationScope","threadPoll","getFilenameToDebugIdMap","registerThread","POLL_RATIO","Worker","isMainThread","defineIntegration","getClient","isPromise"],"mappings":"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"}
{"version":3,"file":"event-loop-block-integration.js","sources":["../../src/event-loop-block-integration.ts"],"sourcesContent":["import { isPromise } from 'node:util/types';\nimport { isMainThread, Worker } from 'node:worker_threads';\nimport type {\n ClientOptions,\n Contexts,\n DsnComponents,\n Event,\n EventHint,\n Integration,\n IntegrationFn,\n ScopeData,\n} from '@sentry/core';\nimport {\n debug,\n defineIntegration,\n getClient,\n getCurrentScope,\n getFilenameToDebugIdMap,\n getGlobalScope,\n getIsolationScope,\n mergeScopeData,\n} from '@sentry/core';\nimport type { NodeClient } from '@sentry/node';\nimport { registerThread, threadPoll } from '@sentry/node-native-stacktrace';\nimport type { ThreadBlockedIntegrationOptions, WorkerStartData } from './common';\nimport { POLL_RATIO } from './common';\n\nconst INTEGRATION_NAME = 'ThreadBlocked';\nconst DEFAULT_THRESHOLD_MS = 1_000;\n\nfunction log(message: string, ...args: unknown[]): void {\n debug.log(`[Sentry Event Loop Blocked] ${message}`, ...args);\n}\n\n/**\n * Gets contexts by calling all event processors. This shouldn't be called until all integrations are setup\n */\nasync function getContexts(client: NodeClient): Promise<Contexts> {\n let event: Event | null = { message: INTEGRATION_NAME };\n const eventHint: EventHint = {};\n\n for (const processor of client.getEventProcessors()) {\n if (event === null) break;\n event = await processor(event, eventHint);\n }\n\n return event?.contexts || {};\n}\n\nfunction getLocalScopeData(): ScopeData {\n const globalScope = getGlobalScope().getScopeData();\n const currentScope = getCurrentScope().getScopeData();\n mergeScopeData(globalScope, currentScope);\n return globalScope;\n}\n\ntype IntegrationInternal = { start: () => void; stop: () => void };\n\nfunction poll(enabled: boolean, clientOptions: ClientOptions): void {\n try {\n const currentSession = getIsolationScope().getSession();\n // We need to copy the session object and remove the toJSON method so it can be sent to the worker\n // serialized without making it a SerializedSession\n const session = currentSession ? { ...currentSession, toJSON: undefined } : undefined;\n const scope = getLocalScopeData();\n // message the worker to tell it the main event loop is still running\n threadPoll(enabled, { session, scope, debugImages: getFilenameToDebugIdMap(clientOptions.stackParser) });\n } catch {\n // we ignore all errors\n }\n}\n\n/**\n * Starts polling\n */\nfunction startPolling(\n client: NodeClient,\n integrationOptions: Partial<ThreadBlockedIntegrationOptions>,\n): IntegrationInternal | undefined {\n if (client.asyncLocalStorageLookup) {\n const { asyncLocalStorage, contextSymbol } = client.asyncLocalStorageLookup;\n registerThread({ asyncLocalStorage, stateLookup: ['_currentContext', contextSymbol] });\n } else {\n registerThread();\n }\n\n let enabled = true;\n\n const initOptions = client.getOptions();\n const pollInterval = (integrationOptions.threshold || DEFAULT_THRESHOLD_MS) / POLL_RATIO;\n\n // unref so timer does not block exit\n setInterval(() => poll(enabled, initOptions), pollInterval).unref();\n\n return {\n start: () => {\n enabled = true;\n },\n stop: () => {\n enabled = false;\n // poll immediately because the timer above might not get a chance to run\n // before the event loop gets blocked\n poll(enabled, initOptions);\n },\n };\n}\n\n/**\n * Starts the worker thread that will monitor the other threads.\n *\n * This function is only called in the main thread.\n */\nasync function startWorker(\n dsn: DsnComponents,\n client: NodeClient,\n integrationOptions: Partial<ThreadBlockedIntegrationOptions>,\n): Promise<void> {\n const contexts = await getContexts(client);\n\n // These will not be accurate if sent later from the worker thread\n delete contexts.app?.app_memory;\n delete contexts.device?.free_memory;\n\n const initOptions = client.getOptions();\n\n const sdkMetadata = client.getSdkMetadata() || {};\n if (sdkMetadata.sdk) {\n sdkMetadata.sdk.integrations = initOptions.integrations.map(i => i.name);\n }\n\n const options: WorkerStartData = {\n debug: debug.isEnabled(),\n dsn,\n tunnel: initOptions.tunnel,\n environment: initOptions.environment || 'production',\n release: initOptions.release,\n dist: initOptions.dist,\n sdkMetadata,\n appRootPath: integrationOptions.appRootPath,\n threshold: integrationOptions.threshold || DEFAULT_THRESHOLD_MS,\n maxEventsPerHour: integrationOptions.maxEventsPerHour || 1,\n staticTags: integrationOptions.staticTags || {},\n contexts,\n };\n\n const worker = new Worker(new URL('./event-loop-block-watchdog.js', import.meta.url), {\n workerData: options,\n // We don't want any Node args like --import to be passed to the worker\n execArgv: [],\n env: { ...process.env, NODE_OPTIONS: undefined },\n });\n\n process.on('exit', () => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n });\n\n worker.once('error', (err: Error) => {\n log('watchdog worker error', err);\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n });\n\n worker.once('exit', (code: number) => {\n log('watchdog worker exit', code);\n });\n\n // Ensure this thread can't block app exit\n worker.unref();\n}\n\nconst _eventLoopBlockIntegration = ((options: Partial<ThreadBlockedIntegrationOptions> = {}) => {\n let polling: IntegrationInternal | undefined;\n\n return {\n name: INTEGRATION_NAME,\n async afterAllSetup(client: NodeClient): Promise<void> {\n const dsn = client.getDsn();\n\n if (!dsn) {\n log('No DSN configured, skipping starting integration');\n return;\n }\n\n // Otel is not setup until after afterAllSetup returns.\n setImmediate(async () => {\n try {\n polling = startPolling(client, options);\n\n if (isMainThread) {\n await startWorker(dsn, client, options);\n }\n } catch (err) {\n log('Failed to start integration', err);\n return;\n }\n });\n },\n start() {\n polling?.start();\n },\n stop() {\n polling?.stop();\n },\n } as Integration & IntegrationInternal;\n}) satisfies IntegrationFn;\n\n/**\n * Monitors the Node.js event loop for blocking behavior and reports blocked events to Sentry.\n *\n * Uses a background worker thread to detect when the main thread is blocked for longer than\n * the configured threshold (default: 1 second).\n *\n * When instrumenting via the `--import` flag, this integration will\n * automatically monitor all worker threads as well.\n *\n * ```js\n * // instrument.mjs\n * import * as Sentry from '@sentry/node';\n * import { eventLoopBlockIntegration } from '@sentry/node-native';\n *\n * Sentry.init({\n * dsn: '__YOUR_DSN__',\n * integrations: [\n * eventLoopBlockIntegration({\n * threshold: 500, // Report blocks longer than 500ms\n * }),\n * ],\n * });\n * ```\n *\n * Start your application with:\n * ```bash\n * node --import instrument.mjs app.mjs\n * ```\n */\nexport const eventLoopBlockIntegration = defineIntegration(_eventLoopBlockIntegration);\n\nexport function disableBlockDetectionForCallback<T>(callback: () => T): T;\nexport function disableBlockDetectionForCallback<T>(callback: () => Promise<T>): Promise<T>;\n/**\n * Disables Event Loop Block detection for the current thread for the duration\n * of the callback.\n *\n * This utility function allows you to disable block detection during operations that\n * are expected to block the event loop, such as intensive computational tasks or\n * synchronous I/O operations.\n */\nexport function disableBlockDetectionForCallback<T>(callback: () => T | Promise<T>): T | Promise<T> {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return callback();\n }\n\n integration.stop();\n\n try {\n const result = callback();\n if (isPromise(result)) {\n return result.finally(() => integration.start());\n }\n\n integration.start();\n return result;\n } catch (error) {\n integration.start();\n throw error;\n }\n}\n\n/**\n * Pauses the block detection integration.\n *\n * This function pauses event loop block detection for the current thread.\n */\nexport function pauseEventLoopBlockDetection(): void {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return;\n }\n\n integration.stop();\n}\n\n/**\n * Restarts the block detection integration.\n *\n * This function restarts event loop block detection for the current thread.\n */\nexport function restartEventLoopBlockDetection(): void {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return;\n }\n\n integration.start();\n}\n"],"names":["debug","getGlobalScope","getCurrentScope","mergeScopeData","getIsolationScope","threadPoll","getFilenameToDebugIdMap","registerThread","POLL_RATIO","Worker","isMainThread","defineIntegration","getClient","isPromise"],"mappings":"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"}
const node_worker_threads = require('node:worker_threads');
const core = require('@sentry/core');
const node = require('@sentry/node');
const nodeNativeStacktrace = require('@sentry-internal/node-native-stacktrace');
const nodeNativeStacktrace = require('@sentry/node-native-stacktrace');
const common = require('./common.js');

@@ -6,0 +6,0 @@

@@ -1,1 +0,1 @@

{"version":3,"file":"event-loop-block-watchdog.js","sources":["../../src/event-loop-block-watchdog.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport type { DebugImage, Event, ScopeData, Session, StackFrame, Thread } from '@sentry/core';\nimport {\n applyScopeDataToEvent,\n createEventEnvelope,\n createSessionEnvelope,\n filenameIsInApp,\n generateSpanId,\n getEnvelopeEndpointWithUrlEncodedAuth,\n makeSession,\n mergeScopeData,\n normalizeUrlToBase,\n Scope,\n stripSentryFramesAndReverse,\n updateSession,\n uuid4,\n} from '@sentry/core';\nimport { makeNodeTransport } from '@sentry/node';\nimport { captureStackTrace, getThreadsLastSeen } from '@sentry-internal/node-native-stacktrace';\nimport type { ThreadState, WorkerStartData } from './common';\nimport { POLL_RATIO } from './common';\n\ntype CurrentScopes = {\n isolationScope: Scope;\n};\n\nconst {\n threshold,\n appRootPath,\n contexts,\n debug,\n dist,\n dsn,\n environment,\n maxEventsPerHour,\n release,\n sdkMetadata,\n staticTags: tags,\n tunnel,\n} = workerData as WorkerStartData;\n\nconst pollInterval = threshold / POLL_RATIO;\nconst triggeredThreads = new Set<string>();\n\nfunction log(...msg: unknown[]): void {\n if (debug) {\n // eslint-disable-next-line no-console\n console.log('[Sentry Event Loop Blocked Watchdog]', ...msg);\n }\n}\n\nfunction createRateLimiter(maxEventsPerHour: number): () => boolean {\n let currentHour = 0;\n let currentCount = 0;\n\n return function isRateLimited(): boolean {\n const hour = new Date().getHours();\n\n if (hour !== currentHour) {\n currentHour = hour;\n currentCount = 0;\n }\n\n if (currentCount >= maxEventsPerHour) {\n if (currentCount === maxEventsPerHour) {\n currentCount += 1;\n log(`Rate limit reached: ${currentCount} events in this hour`);\n }\n return true;\n }\n\n currentCount += 1;\n return false;\n };\n}\n\nconst url = getEnvelopeEndpointWithUrlEncodedAuth(dsn, tunnel, sdkMetadata.sdk);\nconst transport = makeNodeTransport({\n url,\n recordDroppedEvent: () => {\n //\n },\n});\nconst isRateLimited = createRateLimiter(maxEventsPerHour);\n\nasync function sendAbnormalSession(serializedSession: Session | undefined): Promise<void> {\n if (!serializedSession) {\n return;\n }\n\n log('Sending abnormal session');\n const session = makeSession(serializedSession);\n\n updateSession(session, {\n status: 'abnormal',\n abnormal_mechanism: 'anr_foreground',\n release,\n environment,\n });\n\n const envelope = createSessionEnvelope(session, dsn, sdkMetadata, tunnel);\n // Log the envelope so to aid in testing\n log(JSON.stringify(envelope));\n\n await transport.send(envelope);\n}\n\nlog('Started');\n\nfunction prepareStackFrames(stackFrames: StackFrame[] | undefined): StackFrame[] | undefined {\n if (!stackFrames) {\n return undefined;\n }\n\n // Strip Sentry frames and reverse the stack frames so they are in the correct order\n const strippedFrames = stripSentryFramesAndReverse(stackFrames);\n\n for (const frame of strippedFrames) {\n if (!frame.filename) {\n continue;\n }\n\n frame.in_app = filenameIsInApp(frame.filename);\n\n // If we have an app root path, rewrite the filenames to be relative to the app root\n if (appRootPath) {\n frame.filename = normalizeUrlToBase(frame.filename, appRootPath);\n }\n }\n\n return strippedFrames;\n}\n\nfunction stripFileProtocol(filename: string | undefined): string | undefined {\n if (!filename) {\n return undefined;\n }\n return filename.replace(/^file:\\/\\//, '');\n}\n\n// eslint-disable-next-line complexity\nfunction applyDebugMeta(event: Event, debugImages: Record<string, string>): void {\n if (Object.keys(debugImages).length === 0) {\n return;\n }\n\n const normalisedDebugImages = appRootPath ? {} : debugImages;\n if (appRootPath) {\n for (const [path, debugId] of Object.entries(debugImages)) {\n normalisedDebugImages[normalizeUrlToBase(path, appRootPath)] = debugId;\n }\n }\n\n const filenameToDebugId = new Map<string, string>();\n\n for (const exception of event.exception?.values || []) {\n for (const frame of exception.stacktrace?.frames || []) {\n const filename = stripFileProtocol(frame.abs_path || frame.filename);\n if (filename && normalisedDebugImages[filename]) {\n filenameToDebugId.set(filename, normalisedDebugImages[filename]);\n }\n }\n }\n\n for (const thread of event.threads?.values || []) {\n for (const frame of thread.stacktrace?.frames || []) {\n const filename = stripFileProtocol(frame.abs_path || frame.filename);\n if (filename && normalisedDebugImages[filename]) {\n filenameToDebugId.set(filename, normalisedDebugImages[filename]);\n }\n }\n }\n\n if (filenameToDebugId.size > 0) {\n const images: DebugImage[] = [];\n for (const [code_file, debug_id] of filenameToDebugId.entries()) {\n images.push({\n type: 'sourcemap',\n code_file,\n debug_id,\n });\n }\n event.debug_meta = { images };\n }\n}\n\nfunction getExceptionAndThreads(\n crashedThreadId: string,\n threads: ReturnType<typeof captureStackTrace<CurrentScopes, ThreadState>>,\n): Event {\n const crashedThread = threads[crashedThreadId];\n\n return {\n exception: {\n values: [\n {\n type: 'EventLoopBlocked',\n value: `Event Loop Blocked for at least ${threshold} ms`,\n stacktrace: { frames: prepareStackFrames(crashedThread?.frames) },\n // This ensures the UI doesn't say 'Crashed in' for the stack trace\n mechanism: { type: 'ANR' },\n thread_id: crashedThreadId,\n },\n ],\n },\n threads: {\n values: Object.entries(threads).map(([threadId, threadState]) => {\n const crashed = threadId === crashedThreadId;\n\n const thread: Thread = {\n id: threadId,\n name: threadId === '0' ? 'main' : `worker-${threadId}`,\n crashed,\n current: true,\n main: threadId === '0',\n };\n\n if (!crashed) {\n thread.stacktrace = { frames: prepareStackFrames(threadState.frames) };\n }\n\n return thread;\n }),\n },\n };\n}\n\nfunction applyScopeToEvent(event: Event, scope: ScopeData): void {\n applyScopeDataToEvent(event, scope);\n\n if (!event.contexts?.trace) {\n const { traceId, parentSpanId, propagationSpanId } = scope.propagationContext;\n event.contexts = {\n trace: {\n trace_id: traceId,\n span_id: propagationSpanId || generateSpanId(),\n parent_span_id: parentSpanId,\n },\n ...event.contexts,\n };\n }\n}\n\nasync function sendBlockEvent(crashedThreadId: string): Promise<void> {\n if (isRateLimited()) {\n return;\n }\n\n const threads = captureStackTrace<CurrentScopes, ThreadState>();\n const crashedThread = threads[crashedThreadId];\n\n if (!crashedThread) {\n log(`No thread found with ID '${crashedThreadId}'`);\n return;\n }\n\n try {\n await sendAbnormalSession(crashedThread.pollState?.session);\n } catch (error) {\n log(`Failed to send abnormal session for thread '${crashedThreadId}':`, error);\n }\n\n log('Sending event');\n\n const event: Event = {\n event_id: uuid4(),\n contexts,\n release,\n environment,\n dist,\n platform: 'node',\n level: 'error',\n tags,\n ...getExceptionAndThreads(crashedThreadId, threads),\n };\n\n const scope = crashedThread.pollState?.scope\n ? new Scope().update(crashedThread.pollState.scope).getScopeData()\n : new Scope().getScopeData();\n\n if (crashedThread?.asyncState?.isolationScope) {\n // We need to rehydrate the scope from the serialized object with properties beginning with _user, etc\n const isolationScope = Object.assign(new Scope(), crashedThread.asyncState.isolationScope).getScopeData();\n mergeScopeData(scope, isolationScope);\n }\n applyScopeToEvent(event, scope);\n\n const allDebugImages: Record<string, string> = Object.values(threads).reduce((acc, threadState) => {\n return { ...acc, ...threadState.pollState?.debugImages };\n }, {});\n\n applyDebugMeta(event, allDebugImages);\n\n const envelope = createEventEnvelope(event, dsn, sdkMetadata, tunnel);\n // Log the envelope to aid in testing\n log(JSON.stringify(envelope));\n\n await transport.send(envelope);\n await transport.flush(2000);\n}\n\nsetInterval(async () => {\n for (const [threadId, time] of Object.entries(getThreadsLastSeen())) {\n if (time > threshold) {\n if (triggeredThreads.has(threadId)) {\n continue;\n }\n\n log(`Blocked thread detected '${threadId}' last polled ${time} ms ago.`);\n triggeredThreads.add(threadId);\n\n try {\n await sendBlockEvent(threadId);\n } catch (error) {\n log(`Failed to send event for thread '${threadId}':`, error);\n }\n } else {\n triggeredThreads.delete(threadId);\n }\n }\n}, pollInterval);\n"],"names":["workerData","POLL_RATIO","maxEventsPerHour","isRateLimited","getEnvelopeEndpointWithUrlEncodedAuth","makeNodeTransport","makeSession","updateSession","createSessionEnvelope","stripSentryFramesAndReverse","filenameIsInApp","normalizeUrlToBase","applyScopeDataToEvent","generateSpanId","captureStackTrace","uuid4","Scope","mergeScopeData","createEventEnvelope","getThreadsLastSeen"],"mappings":"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"}
{"version":3,"file":"event-loop-block-watchdog.js","sources":["../../src/event-loop-block-watchdog.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport type { DebugImage, Event, ScopeData, Session, StackFrame, Thread } from '@sentry/core';\nimport {\n applyScopeDataToEvent,\n createEventEnvelope,\n createSessionEnvelope,\n filenameIsInApp,\n generateSpanId,\n getEnvelopeEndpointWithUrlEncodedAuth,\n makeSession,\n mergeScopeData,\n normalizeUrlToBase,\n Scope,\n stripSentryFramesAndReverse,\n updateSession,\n uuid4,\n} from '@sentry/core';\nimport { makeNodeTransport } from '@sentry/node';\nimport { captureStackTrace, getThreadsLastSeen } from '@sentry/node-native-stacktrace';\nimport type { ThreadState, WorkerStartData } from './common';\nimport { POLL_RATIO } from './common';\n\ntype CurrentScopes = {\n isolationScope: Scope;\n};\n\nconst {\n threshold,\n appRootPath,\n contexts,\n debug,\n dist,\n dsn,\n environment,\n maxEventsPerHour,\n release,\n sdkMetadata,\n staticTags: tags,\n tunnel,\n} = workerData as WorkerStartData;\n\nconst pollInterval = threshold / POLL_RATIO;\nconst triggeredThreads = new Set<string>();\n\nfunction log(...msg: unknown[]): void {\n if (debug) {\n // eslint-disable-next-line no-console\n console.log('[Sentry Event Loop Blocked Watchdog]', ...msg);\n }\n}\n\nfunction createRateLimiter(maxEventsPerHour: number): () => boolean {\n let currentHour = 0;\n let currentCount = 0;\n\n return function isRateLimited(): boolean {\n const hour = new Date().getHours();\n\n if (hour !== currentHour) {\n currentHour = hour;\n currentCount = 0;\n }\n\n if (currentCount >= maxEventsPerHour) {\n if (currentCount === maxEventsPerHour) {\n currentCount += 1;\n log(`Rate limit reached: ${currentCount} events in this hour`);\n }\n return true;\n }\n\n currentCount += 1;\n return false;\n };\n}\n\nconst url = getEnvelopeEndpointWithUrlEncodedAuth(dsn, tunnel, sdkMetadata.sdk);\nconst transport = makeNodeTransport({\n url,\n recordDroppedEvent: () => {\n //\n },\n});\nconst isRateLimited = createRateLimiter(maxEventsPerHour);\n\nasync function sendAbnormalSession(serializedSession: Session | undefined): Promise<void> {\n if (!serializedSession) {\n return;\n }\n\n log('Sending abnormal session');\n const session = makeSession(serializedSession);\n\n updateSession(session, {\n status: 'abnormal',\n abnormal_mechanism: 'anr_foreground',\n release,\n environment,\n });\n\n const envelope = createSessionEnvelope(session, dsn, sdkMetadata, tunnel);\n // Log the envelope so to aid in testing\n log(JSON.stringify(envelope));\n\n await transport.send(envelope);\n}\n\nlog('Started');\n\nfunction prepareStackFrames(stackFrames: StackFrame[] | undefined): StackFrame[] | undefined {\n if (!stackFrames) {\n return undefined;\n }\n\n // Strip Sentry frames and reverse the stack frames so they are in the correct order\n const strippedFrames = stripSentryFramesAndReverse(stackFrames);\n\n for (const frame of strippedFrames) {\n if (!frame.filename) {\n continue;\n }\n\n frame.in_app = filenameIsInApp(frame.filename);\n\n // If we have an app root path, rewrite the filenames to be relative to the app root\n if (appRootPath) {\n frame.filename = normalizeUrlToBase(frame.filename, appRootPath);\n }\n }\n\n return strippedFrames;\n}\n\nfunction stripFileProtocol(filename: string | undefined): string | undefined {\n if (!filename) {\n return undefined;\n }\n return filename.replace(/^file:\\/\\//, '');\n}\n\n// eslint-disable-next-line complexity\nfunction applyDebugMeta(event: Event, debugImages: Record<string, string>): void {\n if (Object.keys(debugImages).length === 0) {\n return;\n }\n\n const normalisedDebugImages = appRootPath ? {} : debugImages;\n if (appRootPath) {\n for (const [path, debugId] of Object.entries(debugImages)) {\n normalisedDebugImages[normalizeUrlToBase(path, appRootPath)] = debugId;\n }\n }\n\n const filenameToDebugId = new Map<string, string>();\n\n for (const exception of event.exception?.values || []) {\n for (const frame of exception.stacktrace?.frames || []) {\n const filename = stripFileProtocol(frame.abs_path || frame.filename);\n if (filename && normalisedDebugImages[filename]) {\n filenameToDebugId.set(filename, normalisedDebugImages[filename]);\n }\n }\n }\n\n for (const thread of event.threads?.values || []) {\n for (const frame of thread.stacktrace?.frames || []) {\n const filename = stripFileProtocol(frame.abs_path || frame.filename);\n if (filename && normalisedDebugImages[filename]) {\n filenameToDebugId.set(filename, normalisedDebugImages[filename]);\n }\n }\n }\n\n if (filenameToDebugId.size > 0) {\n const images: DebugImage[] = [];\n for (const [code_file, debug_id] of filenameToDebugId.entries()) {\n images.push({\n type: 'sourcemap',\n code_file,\n debug_id,\n });\n }\n event.debug_meta = { images };\n }\n}\n\nfunction getExceptionAndThreads(\n crashedThreadId: string,\n threads: ReturnType<typeof captureStackTrace<CurrentScopes, ThreadState>>,\n): Event {\n const crashedThread = threads[crashedThreadId];\n\n return {\n exception: {\n values: [\n {\n type: 'EventLoopBlocked',\n value: `Event Loop Blocked for at least ${threshold} ms`,\n stacktrace: { frames: prepareStackFrames(crashedThread?.frames) },\n // This ensures the UI doesn't say 'Crashed in' for the stack trace\n mechanism: { type: 'ANR' },\n thread_id: crashedThreadId,\n },\n ],\n },\n threads: {\n values: Object.entries(threads).map(([threadId, threadState]) => {\n const crashed = threadId === crashedThreadId;\n\n const thread: Thread = {\n id: threadId,\n name: threadId === '0' ? 'main' : `worker-${threadId}`,\n crashed,\n current: true,\n main: threadId === '0',\n };\n\n if (!crashed) {\n thread.stacktrace = { frames: prepareStackFrames(threadState.frames) };\n }\n\n return thread;\n }),\n },\n };\n}\n\nfunction applyScopeToEvent(event: Event, scope: ScopeData): void {\n applyScopeDataToEvent(event, scope);\n\n if (!event.contexts?.trace) {\n const { traceId, parentSpanId, propagationSpanId } = scope.propagationContext;\n event.contexts = {\n trace: {\n trace_id: traceId,\n span_id: propagationSpanId || generateSpanId(),\n parent_span_id: parentSpanId,\n },\n ...event.contexts,\n };\n }\n}\n\nasync function sendBlockEvent(crashedThreadId: string): Promise<void> {\n if (isRateLimited()) {\n return;\n }\n\n const threads = captureStackTrace<CurrentScopes, ThreadState>();\n const crashedThread = threads[crashedThreadId];\n\n if (!crashedThread) {\n log(`No thread found with ID '${crashedThreadId}'`);\n return;\n }\n\n try {\n await sendAbnormalSession(crashedThread.pollState?.session);\n } catch (error) {\n log(`Failed to send abnormal session for thread '${crashedThreadId}':`, error);\n }\n\n log('Sending event');\n\n const event: Event = {\n event_id: uuid4(),\n contexts,\n release,\n environment,\n dist,\n platform: 'node',\n level: 'error',\n tags,\n ...getExceptionAndThreads(crashedThreadId, threads),\n };\n\n const scope = crashedThread.pollState?.scope\n ? new Scope().update(crashedThread.pollState.scope).getScopeData()\n : new Scope().getScopeData();\n\n if (crashedThread?.asyncState?.isolationScope) {\n // We need to rehydrate the scope from the serialized object with properties beginning with _user, etc\n const isolationScope = Object.assign(new Scope(), crashedThread.asyncState.isolationScope).getScopeData();\n mergeScopeData(scope, isolationScope);\n }\n applyScopeToEvent(event, scope);\n\n const allDebugImages: Record<string, string> = Object.values(threads).reduce((acc, threadState) => {\n return { ...acc, ...threadState.pollState?.debugImages };\n }, {});\n\n applyDebugMeta(event, allDebugImages);\n\n const envelope = createEventEnvelope(event, dsn, sdkMetadata, tunnel);\n // Log the envelope to aid in testing\n log(JSON.stringify(envelope));\n\n await transport.send(envelope);\n await transport.flush(2000);\n}\n\nsetInterval(async () => {\n for (const [threadId, time] of Object.entries(getThreadsLastSeen())) {\n if (time > threshold) {\n if (triggeredThreads.has(threadId)) {\n continue;\n }\n\n log(`Blocked thread detected '${threadId}' last polled ${time} ms ago.`);\n triggeredThreads.add(threadId);\n\n try {\n await sendBlockEvent(threadId);\n } catch (error) {\n log(`Failed to send event for thread '${threadId}':`, error);\n }\n } else {\n triggeredThreads.delete(threadId);\n }\n }\n}, pollInterval);\n"],"names":["workerData","POLL_RATIO","maxEventsPerHour","isRateLimited","getEnvelopeEndpointWithUrlEncodedAuth","makeNodeTransport","makeSession","updateSession","createSessionEnvelope","stripSentryFramesAndReverse","filenameIsInApp","normalizeUrlToBase","applyScopeDataToEvent","generateSpanId","captureStackTrace","uuid4","Scope","mergeScopeData","createEventEnvelope","getThreadsLastSeen"],"mappings":"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"}
import { isPromise } from 'node:util/types';
import { isMainThread, Worker } from 'node:worker_threads';
import { defineIntegration, debug, getIsolationScope, getFilenameToDebugIdMap, getGlobalScope, getCurrentScope, mergeScopeData, getClient } from '@sentry/core';
import { registerThread, threadPoll } from '@sentry-internal/node-native-stacktrace';
import { registerThread, threadPoll } from '@sentry/node-native-stacktrace';
import { POLL_RATIO } from './common.js';

@@ -6,0 +6,0 @@

@@ -1,1 +0,1 @@

{"version":3,"file":"event-loop-block-integration.js","sources":["../../src/event-loop-block-integration.ts"],"sourcesContent":["import { isPromise } from 'node:util/types';\nimport { isMainThread, Worker } from 'node:worker_threads';\nimport type {\n ClientOptions,\n Contexts,\n DsnComponents,\n Event,\n EventHint,\n Integration,\n IntegrationFn,\n ScopeData,\n} from '@sentry/core';\nimport {\n debug,\n defineIntegration,\n getClient,\n getCurrentScope,\n getFilenameToDebugIdMap,\n getGlobalScope,\n getIsolationScope,\n mergeScopeData,\n} from '@sentry/core';\nimport type { NodeClient } from '@sentry/node';\nimport { registerThread, threadPoll } from '@sentry-internal/node-native-stacktrace';\nimport type { ThreadBlockedIntegrationOptions, WorkerStartData } from './common';\nimport { POLL_RATIO } from './common';\n\nconst INTEGRATION_NAME = 'ThreadBlocked';\nconst DEFAULT_THRESHOLD_MS = 1_000;\n\nfunction log(message: string, ...args: unknown[]): void {\n debug.log(`[Sentry Event Loop Blocked] ${message}`, ...args);\n}\n\n/**\n * Gets contexts by calling all event processors. This shouldn't be called until all integrations are setup\n */\nasync function getContexts(client: NodeClient): Promise<Contexts> {\n let event: Event | null = { message: INTEGRATION_NAME };\n const eventHint: EventHint = {};\n\n for (const processor of client.getEventProcessors()) {\n if (event === null) break;\n event = await processor(event, eventHint);\n }\n\n return event?.contexts || {};\n}\n\nfunction getLocalScopeData(): ScopeData {\n const globalScope = getGlobalScope().getScopeData();\n const currentScope = getCurrentScope().getScopeData();\n mergeScopeData(globalScope, currentScope);\n return globalScope;\n}\n\ntype IntegrationInternal = { start: () => void; stop: () => void };\n\nfunction poll(enabled: boolean, clientOptions: ClientOptions): void {\n try {\n const currentSession = getIsolationScope().getSession();\n // We need to copy the session object and remove the toJSON method so it can be sent to the worker\n // serialized without making it a SerializedSession\n const session = currentSession ? { ...currentSession, toJSON: undefined } : undefined;\n const scope = getLocalScopeData();\n // message the worker to tell it the main event loop is still running\n threadPoll(enabled, { session, scope, debugImages: getFilenameToDebugIdMap(clientOptions.stackParser) });\n } catch {\n // we ignore all errors\n }\n}\n\n/**\n * Starts polling\n */\nfunction startPolling(\n client: NodeClient,\n integrationOptions: Partial<ThreadBlockedIntegrationOptions>,\n): IntegrationInternal | undefined {\n if (client.asyncLocalStorageLookup) {\n const { asyncLocalStorage, contextSymbol } = client.asyncLocalStorageLookup;\n registerThread({ asyncLocalStorage, stateLookup: ['_currentContext', contextSymbol] });\n } else {\n registerThread();\n }\n\n let enabled = true;\n\n const initOptions = client.getOptions();\n const pollInterval = (integrationOptions.threshold || DEFAULT_THRESHOLD_MS) / POLL_RATIO;\n\n // unref so timer does not block exit\n setInterval(() => poll(enabled, initOptions), pollInterval).unref();\n\n return {\n start: () => {\n enabled = true;\n },\n stop: () => {\n enabled = false;\n // poll immediately because the timer above might not get a chance to run\n // before the event loop gets blocked\n poll(enabled, initOptions);\n },\n };\n}\n\n/**\n * Starts the worker thread that will monitor the other threads.\n *\n * This function is only called in the main thread.\n */\nasync function startWorker(\n dsn: DsnComponents,\n client: NodeClient,\n integrationOptions: Partial<ThreadBlockedIntegrationOptions>,\n): Promise<void> {\n const contexts = await getContexts(client);\n\n // These will not be accurate if sent later from the worker thread\n delete contexts.app?.app_memory;\n delete contexts.device?.free_memory;\n\n const initOptions = client.getOptions();\n\n const sdkMetadata = client.getSdkMetadata() || {};\n if (sdkMetadata.sdk) {\n sdkMetadata.sdk.integrations = initOptions.integrations.map(i => i.name);\n }\n\n const options: WorkerStartData = {\n debug: debug.isEnabled(),\n dsn,\n tunnel: initOptions.tunnel,\n environment: initOptions.environment || 'production',\n release: initOptions.release,\n dist: initOptions.dist,\n sdkMetadata,\n appRootPath: integrationOptions.appRootPath,\n threshold: integrationOptions.threshold || DEFAULT_THRESHOLD_MS,\n maxEventsPerHour: integrationOptions.maxEventsPerHour || 1,\n staticTags: integrationOptions.staticTags || {},\n contexts,\n };\n\n const worker = new Worker(new URL('./event-loop-block-watchdog.js', import.meta.url), {\n workerData: options,\n // We don't want any Node args like --import to be passed to the worker\n execArgv: [],\n env: { ...process.env, NODE_OPTIONS: undefined },\n });\n\n process.on('exit', () => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n });\n\n worker.once('error', (err: Error) => {\n log('watchdog worker error', err);\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n });\n\n worker.once('exit', (code: number) => {\n log('watchdog worker exit', code);\n });\n\n // Ensure this thread can't block app exit\n worker.unref();\n}\n\nconst _eventLoopBlockIntegration = ((options: Partial<ThreadBlockedIntegrationOptions> = {}) => {\n let polling: IntegrationInternal | undefined;\n\n return {\n name: INTEGRATION_NAME,\n async afterAllSetup(client: NodeClient): Promise<void> {\n const dsn = client.getDsn();\n\n if (!dsn) {\n log('No DSN configured, skipping starting integration');\n return;\n }\n\n // Otel is not setup until after afterAllSetup returns.\n setImmediate(async () => {\n try {\n polling = startPolling(client, options);\n\n if (isMainThread) {\n await startWorker(dsn, client, options);\n }\n } catch (err) {\n log('Failed to start integration', err);\n return;\n }\n });\n },\n start() {\n polling?.start();\n },\n stop() {\n polling?.stop();\n },\n } as Integration & IntegrationInternal;\n}) satisfies IntegrationFn;\n\n/**\n * Monitors the Node.js event loop for blocking behavior and reports blocked events to Sentry.\n *\n * Uses a background worker thread to detect when the main thread is blocked for longer than\n * the configured threshold (default: 1 second).\n *\n * When instrumenting via the `--import` flag, this integration will\n * automatically monitor all worker threads as well.\n *\n * ```js\n * // instrument.mjs\n * import * as Sentry from '@sentry/node';\n * import { eventLoopBlockIntegration } from '@sentry/node-native';\n *\n * Sentry.init({\n * dsn: '__YOUR_DSN__',\n * integrations: [\n * eventLoopBlockIntegration({\n * threshold: 500, // Report blocks longer than 500ms\n * }),\n * ],\n * });\n * ```\n *\n * Start your application with:\n * ```bash\n * node --import instrument.mjs app.mjs\n * ```\n */\nexport const eventLoopBlockIntegration = defineIntegration(_eventLoopBlockIntegration);\n\nexport function disableBlockDetectionForCallback<T>(callback: () => T): T;\nexport function disableBlockDetectionForCallback<T>(callback: () => Promise<T>): Promise<T>;\n/**\n * Disables Event Loop Block detection for the current thread for the duration\n * of the callback.\n *\n * This utility function allows you to disable block detection during operations that\n * are expected to block the event loop, such as intensive computational tasks or\n * synchronous I/O operations.\n */\nexport function disableBlockDetectionForCallback<T>(callback: () => T | Promise<T>): T | Promise<T> {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return callback();\n }\n\n integration.stop();\n\n try {\n const result = callback();\n if (isPromise(result)) {\n return result.finally(() => integration.start());\n }\n\n integration.start();\n return result;\n } catch (error) {\n integration.start();\n throw error;\n }\n}\n\n/**\n * Pauses the block detection integration.\n *\n * This function pauses event loop block detection for the current thread.\n */\nexport function pauseEventLoopBlockDetection(): void {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return;\n }\n\n integration.stop();\n}\n\n/**\n * Restarts the block detection integration.\n *\n * This function restarts event loop block detection for the current thread.\n */\nexport function restartEventLoopBlockDetection(): void {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return;\n }\n\n integration.start();\n}\n"],"names":[],"mappings":"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"}
{"version":3,"file":"event-loop-block-integration.js","sources":["../../src/event-loop-block-integration.ts"],"sourcesContent":["import { isPromise } from 'node:util/types';\nimport { isMainThread, Worker } from 'node:worker_threads';\nimport type {\n ClientOptions,\n Contexts,\n DsnComponents,\n Event,\n EventHint,\n Integration,\n IntegrationFn,\n ScopeData,\n} from '@sentry/core';\nimport {\n debug,\n defineIntegration,\n getClient,\n getCurrentScope,\n getFilenameToDebugIdMap,\n getGlobalScope,\n getIsolationScope,\n mergeScopeData,\n} from '@sentry/core';\nimport type { NodeClient } from '@sentry/node';\nimport { registerThread, threadPoll } from '@sentry/node-native-stacktrace';\nimport type { ThreadBlockedIntegrationOptions, WorkerStartData } from './common';\nimport { POLL_RATIO } from './common';\n\nconst INTEGRATION_NAME = 'ThreadBlocked';\nconst DEFAULT_THRESHOLD_MS = 1_000;\n\nfunction log(message: string, ...args: unknown[]): void {\n debug.log(`[Sentry Event Loop Blocked] ${message}`, ...args);\n}\n\n/**\n * Gets contexts by calling all event processors. This shouldn't be called until all integrations are setup\n */\nasync function getContexts(client: NodeClient): Promise<Contexts> {\n let event: Event | null = { message: INTEGRATION_NAME };\n const eventHint: EventHint = {};\n\n for (const processor of client.getEventProcessors()) {\n if (event === null) break;\n event = await processor(event, eventHint);\n }\n\n return event?.contexts || {};\n}\n\nfunction getLocalScopeData(): ScopeData {\n const globalScope = getGlobalScope().getScopeData();\n const currentScope = getCurrentScope().getScopeData();\n mergeScopeData(globalScope, currentScope);\n return globalScope;\n}\n\ntype IntegrationInternal = { start: () => void; stop: () => void };\n\nfunction poll(enabled: boolean, clientOptions: ClientOptions): void {\n try {\n const currentSession = getIsolationScope().getSession();\n // We need to copy the session object and remove the toJSON method so it can be sent to the worker\n // serialized without making it a SerializedSession\n const session = currentSession ? { ...currentSession, toJSON: undefined } : undefined;\n const scope = getLocalScopeData();\n // message the worker to tell it the main event loop is still running\n threadPoll(enabled, { session, scope, debugImages: getFilenameToDebugIdMap(clientOptions.stackParser) });\n } catch {\n // we ignore all errors\n }\n}\n\n/**\n * Starts polling\n */\nfunction startPolling(\n client: NodeClient,\n integrationOptions: Partial<ThreadBlockedIntegrationOptions>,\n): IntegrationInternal | undefined {\n if (client.asyncLocalStorageLookup) {\n const { asyncLocalStorage, contextSymbol } = client.asyncLocalStorageLookup;\n registerThread({ asyncLocalStorage, stateLookup: ['_currentContext', contextSymbol] });\n } else {\n registerThread();\n }\n\n let enabled = true;\n\n const initOptions = client.getOptions();\n const pollInterval = (integrationOptions.threshold || DEFAULT_THRESHOLD_MS) / POLL_RATIO;\n\n // unref so timer does not block exit\n setInterval(() => poll(enabled, initOptions), pollInterval).unref();\n\n return {\n start: () => {\n enabled = true;\n },\n stop: () => {\n enabled = false;\n // poll immediately because the timer above might not get a chance to run\n // before the event loop gets blocked\n poll(enabled, initOptions);\n },\n };\n}\n\n/**\n * Starts the worker thread that will monitor the other threads.\n *\n * This function is only called in the main thread.\n */\nasync function startWorker(\n dsn: DsnComponents,\n client: NodeClient,\n integrationOptions: Partial<ThreadBlockedIntegrationOptions>,\n): Promise<void> {\n const contexts = await getContexts(client);\n\n // These will not be accurate if sent later from the worker thread\n delete contexts.app?.app_memory;\n delete contexts.device?.free_memory;\n\n const initOptions = client.getOptions();\n\n const sdkMetadata = client.getSdkMetadata() || {};\n if (sdkMetadata.sdk) {\n sdkMetadata.sdk.integrations = initOptions.integrations.map(i => i.name);\n }\n\n const options: WorkerStartData = {\n debug: debug.isEnabled(),\n dsn,\n tunnel: initOptions.tunnel,\n environment: initOptions.environment || 'production',\n release: initOptions.release,\n dist: initOptions.dist,\n sdkMetadata,\n appRootPath: integrationOptions.appRootPath,\n threshold: integrationOptions.threshold || DEFAULT_THRESHOLD_MS,\n maxEventsPerHour: integrationOptions.maxEventsPerHour || 1,\n staticTags: integrationOptions.staticTags || {},\n contexts,\n };\n\n const worker = new Worker(new URL('./event-loop-block-watchdog.js', import.meta.url), {\n workerData: options,\n // We don't want any Node args like --import to be passed to the worker\n execArgv: [],\n env: { ...process.env, NODE_OPTIONS: undefined },\n });\n\n process.on('exit', () => {\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n });\n\n worker.once('error', (err: Error) => {\n log('watchdog worker error', err);\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n worker.terminate();\n });\n\n worker.once('exit', (code: number) => {\n log('watchdog worker exit', code);\n });\n\n // Ensure this thread can't block app exit\n worker.unref();\n}\n\nconst _eventLoopBlockIntegration = ((options: Partial<ThreadBlockedIntegrationOptions> = {}) => {\n let polling: IntegrationInternal | undefined;\n\n return {\n name: INTEGRATION_NAME,\n async afterAllSetup(client: NodeClient): Promise<void> {\n const dsn = client.getDsn();\n\n if (!dsn) {\n log('No DSN configured, skipping starting integration');\n return;\n }\n\n // Otel is not setup until after afterAllSetup returns.\n setImmediate(async () => {\n try {\n polling = startPolling(client, options);\n\n if (isMainThread) {\n await startWorker(dsn, client, options);\n }\n } catch (err) {\n log('Failed to start integration', err);\n return;\n }\n });\n },\n start() {\n polling?.start();\n },\n stop() {\n polling?.stop();\n },\n } as Integration & IntegrationInternal;\n}) satisfies IntegrationFn;\n\n/**\n * Monitors the Node.js event loop for blocking behavior and reports blocked events to Sentry.\n *\n * Uses a background worker thread to detect when the main thread is blocked for longer than\n * the configured threshold (default: 1 second).\n *\n * When instrumenting via the `--import` flag, this integration will\n * automatically monitor all worker threads as well.\n *\n * ```js\n * // instrument.mjs\n * import * as Sentry from '@sentry/node';\n * import { eventLoopBlockIntegration } from '@sentry/node-native';\n *\n * Sentry.init({\n * dsn: '__YOUR_DSN__',\n * integrations: [\n * eventLoopBlockIntegration({\n * threshold: 500, // Report blocks longer than 500ms\n * }),\n * ],\n * });\n * ```\n *\n * Start your application with:\n * ```bash\n * node --import instrument.mjs app.mjs\n * ```\n */\nexport const eventLoopBlockIntegration = defineIntegration(_eventLoopBlockIntegration);\n\nexport function disableBlockDetectionForCallback<T>(callback: () => T): T;\nexport function disableBlockDetectionForCallback<T>(callback: () => Promise<T>): Promise<T>;\n/**\n * Disables Event Loop Block detection for the current thread for the duration\n * of the callback.\n *\n * This utility function allows you to disable block detection during operations that\n * are expected to block the event loop, such as intensive computational tasks or\n * synchronous I/O operations.\n */\nexport function disableBlockDetectionForCallback<T>(callback: () => T | Promise<T>): T | Promise<T> {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return callback();\n }\n\n integration.stop();\n\n try {\n const result = callback();\n if (isPromise(result)) {\n return result.finally(() => integration.start());\n }\n\n integration.start();\n return result;\n } catch (error) {\n integration.start();\n throw error;\n }\n}\n\n/**\n * Pauses the block detection integration.\n *\n * This function pauses event loop block detection for the current thread.\n */\nexport function pauseEventLoopBlockDetection(): void {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return;\n }\n\n integration.stop();\n}\n\n/**\n * Restarts the block detection integration.\n *\n * This function restarts event loop block detection for the current thread.\n */\nexport function restartEventLoopBlockDetection(): void {\n const integration = getClient()?.getIntegrationByName(INTEGRATION_NAME) as IntegrationInternal | undefined;\n\n if (!integration) {\n return;\n }\n\n integration.start();\n}\n"],"names":[],"mappings":"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"}
import { workerData } from 'node:worker_threads';
import { getEnvelopeEndpointWithUrlEncodedAuth, uuid4, Scope, mergeScopeData, createEventEnvelope, makeSession, updateSession, createSessionEnvelope, applyScopeDataToEvent, generateSpanId, normalizeUrlToBase, stripSentryFramesAndReverse, filenameIsInApp } from '@sentry/core';
import { makeNodeTransport } from '@sentry/node';
import { getThreadsLastSeen, captureStackTrace } from '@sentry-internal/node-native-stacktrace';
import { getThreadsLastSeen, captureStackTrace } from '@sentry/node-native-stacktrace';
import { POLL_RATIO } from './common.js';

@@ -6,0 +6,0 @@

@@ -1,1 +0,1 @@

{"version":3,"file":"event-loop-block-watchdog.js","sources":["../../src/event-loop-block-watchdog.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport type { DebugImage, Event, ScopeData, Session, StackFrame, Thread } from '@sentry/core';\nimport {\n applyScopeDataToEvent,\n createEventEnvelope,\n createSessionEnvelope,\n filenameIsInApp,\n generateSpanId,\n getEnvelopeEndpointWithUrlEncodedAuth,\n makeSession,\n mergeScopeData,\n normalizeUrlToBase,\n Scope,\n stripSentryFramesAndReverse,\n updateSession,\n uuid4,\n} from '@sentry/core';\nimport { makeNodeTransport } from '@sentry/node';\nimport { captureStackTrace, getThreadsLastSeen } from '@sentry-internal/node-native-stacktrace';\nimport type { ThreadState, WorkerStartData } from './common';\nimport { POLL_RATIO } from './common';\n\ntype CurrentScopes = {\n isolationScope: Scope;\n};\n\nconst {\n threshold,\n appRootPath,\n contexts,\n debug,\n dist,\n dsn,\n environment,\n maxEventsPerHour,\n release,\n sdkMetadata,\n staticTags: tags,\n tunnel,\n} = workerData as WorkerStartData;\n\nconst pollInterval = threshold / POLL_RATIO;\nconst triggeredThreads = new Set<string>();\n\nfunction log(...msg: unknown[]): void {\n if (debug) {\n // eslint-disable-next-line no-console\n console.log('[Sentry Event Loop Blocked Watchdog]', ...msg);\n }\n}\n\nfunction createRateLimiter(maxEventsPerHour: number): () => boolean {\n let currentHour = 0;\n let currentCount = 0;\n\n return function isRateLimited(): boolean {\n const hour = new Date().getHours();\n\n if (hour !== currentHour) {\n currentHour = hour;\n currentCount = 0;\n }\n\n if (currentCount >= maxEventsPerHour) {\n if (currentCount === maxEventsPerHour) {\n currentCount += 1;\n log(`Rate limit reached: ${currentCount} events in this hour`);\n }\n return true;\n }\n\n currentCount += 1;\n return false;\n };\n}\n\nconst url = getEnvelopeEndpointWithUrlEncodedAuth(dsn, tunnel, sdkMetadata.sdk);\nconst transport = makeNodeTransport({\n url,\n recordDroppedEvent: () => {\n //\n },\n});\nconst isRateLimited = createRateLimiter(maxEventsPerHour);\n\nasync function sendAbnormalSession(serializedSession: Session | undefined): Promise<void> {\n if (!serializedSession) {\n return;\n }\n\n log('Sending abnormal session');\n const session = makeSession(serializedSession);\n\n updateSession(session, {\n status: 'abnormal',\n abnormal_mechanism: 'anr_foreground',\n release,\n environment,\n });\n\n const envelope = createSessionEnvelope(session, dsn, sdkMetadata, tunnel);\n // Log the envelope so to aid in testing\n log(JSON.stringify(envelope));\n\n await transport.send(envelope);\n}\n\nlog('Started');\n\nfunction prepareStackFrames(stackFrames: StackFrame[] | undefined): StackFrame[] | undefined {\n if (!stackFrames) {\n return undefined;\n }\n\n // Strip Sentry frames and reverse the stack frames so they are in the correct order\n const strippedFrames = stripSentryFramesAndReverse(stackFrames);\n\n for (const frame of strippedFrames) {\n if (!frame.filename) {\n continue;\n }\n\n frame.in_app = filenameIsInApp(frame.filename);\n\n // If we have an app root path, rewrite the filenames to be relative to the app root\n if (appRootPath) {\n frame.filename = normalizeUrlToBase(frame.filename, appRootPath);\n }\n }\n\n return strippedFrames;\n}\n\nfunction stripFileProtocol(filename: string | undefined): string | undefined {\n if (!filename) {\n return undefined;\n }\n return filename.replace(/^file:\\/\\//, '');\n}\n\n// eslint-disable-next-line complexity\nfunction applyDebugMeta(event: Event, debugImages: Record<string, string>): void {\n if (Object.keys(debugImages).length === 0) {\n return;\n }\n\n const normalisedDebugImages = appRootPath ? {} : debugImages;\n if (appRootPath) {\n for (const [path, debugId] of Object.entries(debugImages)) {\n normalisedDebugImages[normalizeUrlToBase(path, appRootPath)] = debugId;\n }\n }\n\n const filenameToDebugId = new Map<string, string>();\n\n for (const exception of event.exception?.values || []) {\n for (const frame of exception.stacktrace?.frames || []) {\n const filename = stripFileProtocol(frame.abs_path || frame.filename);\n if (filename && normalisedDebugImages[filename]) {\n filenameToDebugId.set(filename, normalisedDebugImages[filename]);\n }\n }\n }\n\n for (const thread of event.threads?.values || []) {\n for (const frame of thread.stacktrace?.frames || []) {\n const filename = stripFileProtocol(frame.abs_path || frame.filename);\n if (filename && normalisedDebugImages[filename]) {\n filenameToDebugId.set(filename, normalisedDebugImages[filename]);\n }\n }\n }\n\n if (filenameToDebugId.size > 0) {\n const images: DebugImage[] = [];\n for (const [code_file, debug_id] of filenameToDebugId.entries()) {\n images.push({\n type: 'sourcemap',\n code_file,\n debug_id,\n });\n }\n event.debug_meta = { images };\n }\n}\n\nfunction getExceptionAndThreads(\n crashedThreadId: string,\n threads: ReturnType<typeof captureStackTrace<CurrentScopes, ThreadState>>,\n): Event {\n const crashedThread = threads[crashedThreadId];\n\n return {\n exception: {\n values: [\n {\n type: 'EventLoopBlocked',\n value: `Event Loop Blocked for at least ${threshold} ms`,\n stacktrace: { frames: prepareStackFrames(crashedThread?.frames) },\n // This ensures the UI doesn't say 'Crashed in' for the stack trace\n mechanism: { type: 'ANR' },\n thread_id: crashedThreadId,\n },\n ],\n },\n threads: {\n values: Object.entries(threads).map(([threadId, threadState]) => {\n const crashed = threadId === crashedThreadId;\n\n const thread: Thread = {\n id: threadId,\n name: threadId === '0' ? 'main' : `worker-${threadId}`,\n crashed,\n current: true,\n main: threadId === '0',\n };\n\n if (!crashed) {\n thread.stacktrace = { frames: prepareStackFrames(threadState.frames) };\n }\n\n return thread;\n }),\n },\n };\n}\n\nfunction applyScopeToEvent(event: Event, scope: ScopeData): void {\n applyScopeDataToEvent(event, scope);\n\n if (!event.contexts?.trace) {\n const { traceId, parentSpanId, propagationSpanId } = scope.propagationContext;\n event.contexts = {\n trace: {\n trace_id: traceId,\n span_id: propagationSpanId || generateSpanId(),\n parent_span_id: parentSpanId,\n },\n ...event.contexts,\n };\n }\n}\n\nasync function sendBlockEvent(crashedThreadId: string): Promise<void> {\n if (isRateLimited()) {\n return;\n }\n\n const threads = captureStackTrace<CurrentScopes, ThreadState>();\n const crashedThread = threads[crashedThreadId];\n\n if (!crashedThread) {\n log(`No thread found with ID '${crashedThreadId}'`);\n return;\n }\n\n try {\n await sendAbnormalSession(crashedThread.pollState?.session);\n } catch (error) {\n log(`Failed to send abnormal session for thread '${crashedThreadId}':`, error);\n }\n\n log('Sending event');\n\n const event: Event = {\n event_id: uuid4(),\n contexts,\n release,\n environment,\n dist,\n platform: 'node',\n level: 'error',\n tags,\n ...getExceptionAndThreads(crashedThreadId, threads),\n };\n\n const scope = crashedThread.pollState?.scope\n ? new Scope().update(crashedThread.pollState.scope).getScopeData()\n : new Scope().getScopeData();\n\n if (crashedThread?.asyncState?.isolationScope) {\n // We need to rehydrate the scope from the serialized object with properties beginning with _user, etc\n const isolationScope = Object.assign(new Scope(), crashedThread.asyncState.isolationScope).getScopeData();\n mergeScopeData(scope, isolationScope);\n }\n applyScopeToEvent(event, scope);\n\n const allDebugImages: Record<string, string> = Object.values(threads).reduce((acc, threadState) => {\n return { ...acc, ...threadState.pollState?.debugImages };\n }, {});\n\n applyDebugMeta(event, allDebugImages);\n\n const envelope = createEventEnvelope(event, dsn, sdkMetadata, tunnel);\n // Log the envelope to aid in testing\n log(JSON.stringify(envelope));\n\n await transport.send(envelope);\n await transport.flush(2000);\n}\n\nsetInterval(async () => {\n for (const [threadId, time] of Object.entries(getThreadsLastSeen())) {\n if (time > threshold) {\n if (triggeredThreads.has(threadId)) {\n continue;\n }\n\n log(`Blocked thread detected '${threadId}' last polled ${time} ms ago.`);\n triggeredThreads.add(threadId);\n\n try {\n await sendBlockEvent(threadId);\n } catch (error) {\n log(`Failed to send event for thread '${threadId}':`, error);\n }\n } else {\n triggeredThreads.delete(threadId);\n }\n }\n}, pollInterval);\n"],"names":["maxEventsPerHour","isRateLimited"],"mappings":";;;;;;AA0BA,MAAM;AAAA,EACJ,SAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,GAAA;AAAA,EACA,WAAA;AAAA,EACA,gBAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA,UAAA,EAAY,IAAA;AAAA,EACZ;AACF,CAAA,GAAI,UAAA;AAEJ,MAAM,eAAe,SAAA,GAAY,UAAA;AACjC,MAAM,gBAAA,uBAAuB,GAAA,EAAY;AAEzC,SAAS,OAAO,GAAA,EAAsB;AACpC,EAAA,IAAI,KAAA,EAAO;AAET,IAAA,OAAA,CAAQ,GAAA,CAAI,sCAAA,EAAwC,GAAG,GAAG,CAAA;AAAA,EAC5D;AACF;AAEA,SAAS,kBAAkBA,iBAAAA,EAAyC;AAClE,EAAA,IAAI,WAAA,GAAc,CAAA;AAClB,EAAA,IAAI,YAAA,GAAe,CAAA;AAEnB,EAAA,OAAO,SAASC,cAAAA,GAAyB;AACvC,IAAA,MAAM,IAAA,GAAA,iBAAO,IAAI,IAAA,EAAK,EAAE,QAAA,EAAS;AAEjC,IAAA,IAAI,SAAS,WAAA,EAAa;AACxB,MAAA,WAAA,GAAc,IAAA;AACd,MAAA,YAAA,GAAe,CAAA;AAAA,IACjB;AAEA,IAAA,IAAI,gBAAgBD,iBAAAA,EAAkB;AACpC,MAAA,IAAI,iBAAiBA,iBAAAA,EAAkB;AACrC,QAAA,YAAA,IAAgB,CAAA;AAChB,QAAA,GAAA,CAAI,CAAA,oBAAA,EAAuB,YAAY,CAAA,oBAAA,CAAsB,CAAA;AAAA,MAC/D;AACA,MAAA,OAAO,IAAA;AAAA,IACT;AAEA,IAAA,YAAA,IAAgB,CAAA;AAChB,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AACF;AAEA,MAAM,GAAA,GAAM,qCAAA,CAAsC,GAAA,EAAK,MAAA,EAAQ,YAAY,GAAG,CAAA;AAC9E,MAAM,YAAY,iBAAA,CAAkB;AAAA,EAClC,GAAA;AAAA,EACA,oBAAoB,MAAM;AAAA,EAE1B;AACF,CAAC,CAAA;AACD,MAAM,aAAA,GAAgB,kBAAkB,gBAAgB,CAAA;AAExD,eAAe,oBAAoB,iBAAA,EAAuD;AACxF,EAAA,IAAI,CAAC,iBAAA,EAAmB;AACtB,IAAA;AAAA,EACF;AAEA,EAAA,GAAA,CAAI,0BAA0B,CAAA;AAC9B,EAAA,MAAM,OAAA,GAAU,YAAY,iBAAiB,CAAA;AAE7C,EAAA,aAAA,CAAc,OAAA,EAAS;AAAA,IACrB,MAAA,EAAQ,UAAA;AAAA,IACR,kBAAA,EAAoB,gBAAA;AAAA,IACpB,OAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,QAAA,GAAW,qBAAA,CAAsB,OAAA,EAAS,GAAA,EAAK,aAAa,MAAM,CAAA;AAExE,EAAA,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AAE5B,EAAA,MAAM,SAAA,CAAU,KAAK,QAAQ,CAAA;AAC/B;AAEA,GAAA,CAAI,SAAS,CAAA;AAEb,SAAS,mBAAmB,WAAA,EAAiE;AAC3F,EAAA,IAAI,CAAC,WAAA,EAAa;AAChB,IAAA,OAAO,MAAA;AAAA,EACT;AAGA,EAAA,MAAM,cAAA,GAAiB,4BAA4B,WAAW,CAAA;AAE9D,EAAA,KAAA,MAAW,SAAS,cAAA,EAAgB;AAClC,IAAA,IAAI,CAAC,MAAM,QAAA,EAAU;AACnB,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,CAAM,MAAA,GAAS,eAAA,CAAgB,KAAA,CAAM,QAAQ,CAAA;AAG7C,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,KAAA,CAAM,QAAA,GAAW,kBAAA,CAAmB,KAAA,CAAM,QAAA,EAAU,WAAW,CAAA;AAAA,IACjE;AAAA,EACF;AAEA,EAAA,OAAO,cAAA;AACT;AAEA,SAAS,kBAAkB,QAAA,EAAkD;AAC3E,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,YAAA,EAAc,EAAE,CAAA;AAC1C;AAGA,SAAS,cAAA,CAAe,OAAc,WAAA,EAA2C;AAC/E,EAAA,IAAI,MAAA,CAAO,IAAA,CAAK,WAAW,CAAA,CAAE,WAAW,CAAA,EAAG;AACzC,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,qBAAA,GAAwB,WAAA,GAAc,EAAC,GAAI,WAAA;AACjD,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,KAAA,MAAW,CAAC,IAAA,EAAM,OAAO,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AACzD,MAAA,qBAAA,CAAsB,kBAAA,CAAmB,IAAA,EAAM,WAAW,CAAC,CAAA,GAAI,OAAA;AAAA,IACjE;AAAA,EACF;AAEA,EAAA,MAAM,iBAAA,uBAAwB,GAAA,EAAoB;AAElD,EAAA,KAAA,MAAW,SAAA,IAAa,KAAA,CAAM,SAAA,EAAW,MAAA,IAAU,EAAC,EAAG;AACrD,IAAA,KAAA,MAAW,KAAA,IAAS,SAAA,CAAU,UAAA,EAAY,MAAA,IAAU,EAAC,EAAG;AACtD,MAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,KAAA,CAAM,QAAA,IAAY,MAAM,QAAQ,CAAA;AACnE,MAAA,IAAI,QAAA,IAAY,qBAAA,CAAsB,QAAQ,CAAA,EAAG;AAC/C,QAAA,iBAAA,CAAkB,GAAA,CAAI,QAAA,EAAU,qBAAA,CAAsB,QAAQ,CAAC,CAAA;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AAEA,EAAA,KAAA,MAAW,MAAA,IAAU,KAAA,CAAM,OAAA,EAAS,MAAA,IAAU,EAAC,EAAG;AAChD,IAAA,KAAA,MAAW,KAAA,IAAS,MAAA,CAAO,UAAA,EAAY,MAAA,IAAU,EAAC,EAAG;AACnD,MAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,KAAA,CAAM,QAAA,IAAY,MAAM,QAAQ,CAAA;AACnE,MAAA,IAAI,QAAA,IAAY,qBAAA,CAAsB,QAAQ,CAAA,EAAG;AAC/C,QAAA,iBAAA,CAAkB,GAAA,CAAI,QAAA,EAAU,qBAAA,CAAsB,QAAQ,CAAC,CAAA;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,iBAAA,CAAkB,OAAO,CAAA,EAAG;AAC9B,IAAA,MAAM,SAAuB,EAAC;AAC9B,IAAA,KAAA,MAAW,CAAC,SAAA,EAAW,QAAQ,CAAA,IAAK,iBAAA,CAAkB,SAAQ,EAAG;AAC/D,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,WAAA;AAAA,QACN,SAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH;AACA,IAAA,KAAA,CAAM,UAAA,GAAa,EAAE,MAAA,EAAO;AAAA,EAC9B;AACF;AAEA,SAAS,sBAAA,CACP,iBACA,OAAA,EACO;AACP,EAAA,MAAM,aAAA,GAAgB,QAAQ,eAAe,CAAA;AAE7C,EAAA,OAAO;AAAA,IACL,SAAA,EAAW;AAAA,MACT,MAAA,EAAQ;AAAA,QACN;AAAA,UACE,IAAA,EAAM,kBAAA;AAAA,UACN,KAAA,EAAO,mCAAmC,SAAS,CAAA,GAAA,CAAA;AAAA,UACnD,YAAY,EAAE,MAAA,EAAQ,kBAAA,CAAmB,aAAA,EAAe,MAAM,CAAA,EAAE;AAAA;AAAA,UAEhE,SAAA,EAAW,EAAE,IAAA,EAAM,KAAA,EAAM;AAAA,UACzB,SAAA,EAAW;AAAA;AACb;AACF,KACF;AAAA,IACA,OAAA,EAAS;AAAA,MACP,MAAA,EAAQ,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,CAAE,IAAI,CAAC,CAAC,QAAA,EAAU,WAAW,CAAA,KAAM;AAC/D,QAAA,MAAM,UAAU,QAAA,KAAa,eAAA;AAE7B,QAAA,MAAM,MAAA,GAAiB;AAAA,UACrB,EAAA,EAAI,QAAA;AAAA,UACJ,IAAA,EAAM,QAAA,KAAa,GAAA,GAAM,MAAA,GAAS,UAAU,QAAQ,CAAA,CAAA;AAAA,UACpD,OAAA;AAAA,UACA,OAAA,EAAS,IAAA;AAAA,UACT,MAAM,QAAA,KAAa;AAAA,SACrB;AAEA,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA,MAAA,CAAO,aAAa,EAAE,MAAA,EAAQ,kBAAA,CAAmB,WAAA,CAAY,MAAM,CAAA,EAAE;AAAA,QACvE;AAEA,QAAA,OAAO,MAAA;AAAA,MACT,CAAC;AAAA;AACH,GACF;AACF;AAEA,SAAS,iBAAA,CAAkB,OAAc,KAAA,EAAwB;AAC/D,EAAA,qBAAA,CAAsB,OAAO,KAAK,CAAA;AAElC,EAAA,IAAI,CAAC,KAAA,CAAM,QAAA,EAAU,KAAA,EAAO;AAC1B,IAAA,MAAM,EAAE,OAAA,EAAS,YAAA,EAAc,iBAAA,KAAsB,KAAA,CAAM,kBAAA;AAC3D,IAAA,KAAA,CAAM,QAAA,GAAW;AAAA,MACf,KAAA,EAAO;AAAA,QACL,QAAA,EAAU,OAAA;AAAA,QACV,OAAA,EAAS,qBAAqB,cAAA,EAAe;AAAA,QAC7C,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,GAAG,KAAA,CAAM;AAAA,KACX;AAAA,EACF;AACF;AAEA,eAAe,eAAe,eAAA,EAAwC;AACpE,EAAA,IAAI,eAAc,EAAG;AACnB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,UAAU,iBAAA,EAA8C;AAC9D,EAAA,MAAM,aAAA,GAAgB,QAAQ,eAAe,CAAA;AAE7C,EAAA,IAAI,CAAC,aAAA,EAAe;AAClB,IAAA,GAAA,CAAI,CAAA,yBAAA,EAA4B,eAAe,CAAA,CAAA,CAAG,CAAA;AAClD,IAAA;AAAA,EACF;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,mBAAA,CAAoB,aAAA,CAAc,SAAA,EAAW,OAAO,CAAA;AAAA,EAC5D,SAAS,KAAA,EAAO;AACd,IAAA,GAAA,CAAI,CAAA,4CAAA,EAA+C,eAAe,CAAA,EAAA,CAAA,EAAM,KAAK,CAAA;AAAA,EAC/E;AAEA,EAAA,GAAA,CAAI,eAAe,CAAA;AAEnB,EAAA,MAAM,KAAA,GAAe;AAAA,IACnB,UAAU,KAAA,EAAM;AAAA,IAChB,QAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA;AAAA,IACA,IAAA;AAAA,IACA,QAAA,EAAU,MAAA;AAAA,IACV,KAAA,EAAO,OAAA;AAAA,IACP,IAAA;AAAA,IACA,GAAG,sBAAA,CAAuB,eAAA,EAAiB,OAAO;AAAA,GACpD;AAEA,EAAA,MAAM,QAAQ,aAAA,CAAc,SAAA,EAAW,KAAA,GACnC,IAAI,OAAM,CAAE,MAAA,CAAO,aAAA,CAAc,SAAA,CAAU,KAAK,CAAA,CAAE,YAAA,KAClD,IAAI,KAAA,GAAQ,YAAA,EAAa;AAE7B,EAAA,IAAI,aAAA,EAAe,YAAY,cAAA,EAAgB;AAE7C,IAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,MAAA,CAAO,IAAI,KAAA,IAAS,aAAA,CAAc,UAAA,CAAW,cAAc,CAAA,CAAE,YAAA,EAAa;AACxG,IAAA,cAAA,CAAe,OAAO,cAAc,CAAA;AAAA,EACtC;AACA,EAAA,iBAAA,CAAkB,OAAO,KAAK,CAAA;AAE9B,EAAA,MAAM,cAAA,GAAyC,OAAO,MAAA,CAAO,OAAO,EAAE,MAAA,CAAO,CAAC,KAAK,WAAA,KAAgB;AACjG,IAAA,OAAO,EAAE,GAAG,GAAA,EAAK,GAAG,WAAA,CAAY,WAAW,WAAA,EAAY;AAAA,EACzD,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,cAAA,CAAe,OAAO,cAAc,CAAA;AAEpC,EAAA,MAAM,QAAA,GAAW,mBAAA,CAAoB,KAAA,EAAO,GAAA,EAAK,aAAa,MAAM,CAAA;AAEpE,EAAA,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAC,CAAA;AAE5B,EAAA,MAAM,SAAA,CAAU,KAAK,QAAQ,CAAA;AAC7B,EAAA,MAAM,SAAA,CAAU,MAAM,GAAI,CAAA;AAC5B;AAEA,WAAA,CAAY,YAAY;AACtB,EAAA,KAAA,MAAW,CAAC,UAAU,IAAI,CAAA,IAAK,OAAO,OAAA,CAAQ,kBAAA,EAAoB,CAAA,EAAG;AACnE,IAAA,IAAI,OAAO,SAAA,EAAW;AACpB,MAAA,IAAI,gBAAA,CAAiB,GAAA,CAAI,QAAQ,CAAA,EAAG;AAClC,QAAA;AAAA,MACF;AAEA,MAAA,GAAA,CAAI,CAAA,yBAAA,EAA4B,QAAQ,CAAA,cAAA,EAAiB,IAAI,CAAA,QAAA,CAAU,CAAA;AACvE,MAAA,gBAAA,CAAiB,IAAI,QAAQ,CAAA;AAE7B,MAAA,IAAI;AACF,QAAA,MAAM,eAAe,QAAQ,CAAA;AAAA,MAC/B,SAAS,KAAA,EAAO;AACd,QAAA,GAAA,CAAI,CAAA,iCAAA,EAAoC,QAAQ,CAAA,EAAA,CAAA,EAAM,KAAK,CAAA;AAAA,MAC7D;AAAA,IACF,CAAA,MAAO;AACL,MAAA,gBAAA,CAAiB,OAAO,QAAQ,CAAA;AAAA,IAClC;AAAA,EACF;AACF,CAAA,EAAG,YAAY,CAAA"}
{"version":3,"file":"event-loop-block-watchdog.js","sources":["../../src/event-loop-block-watchdog.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport type { DebugImage, Event, ScopeData, Session, StackFrame, Thread } from '@sentry/core';\nimport {\n applyScopeDataToEvent,\n createEventEnvelope,\n createSessionEnvelope,\n filenameIsInApp,\n generateSpanId,\n getEnvelopeEndpointWithUrlEncodedAuth,\n makeSession,\n mergeScopeData,\n normalizeUrlToBase,\n Scope,\n stripSentryFramesAndReverse,\n updateSession,\n uuid4,\n} from '@sentry/core';\nimport { makeNodeTransport } from '@sentry/node';\nimport { captureStackTrace, getThreadsLastSeen } from '@sentry/node-native-stacktrace';\nimport type { ThreadState, WorkerStartData } from './common';\nimport { POLL_RATIO } from './common';\n\ntype CurrentScopes = {\n isolationScope: Scope;\n};\n\nconst {\n threshold,\n appRootPath,\n contexts,\n debug,\n dist,\n dsn,\n environment,\n maxEventsPerHour,\n release,\n sdkMetadata,\n staticTags: tags,\n tunnel,\n} = workerData as WorkerStartData;\n\nconst pollInterval = threshold / POLL_RATIO;\nconst triggeredThreads = new Set<string>();\n\nfunction log(...msg: unknown[]): void {\n if (debug) {\n // eslint-disable-next-line no-console\n console.log('[Sentry Event Loop Blocked Watchdog]', ...msg);\n }\n}\n\nfunction createRateLimiter(maxEventsPerHour: number): () => boolean {\n let currentHour = 0;\n let currentCount = 0;\n\n return function isRateLimited(): boolean {\n const hour = new Date().getHours();\n\n if (hour !== currentHour) {\n currentHour = hour;\n currentCount = 0;\n }\n\n if (currentCount >= maxEventsPerHour) {\n if (currentCount === maxEventsPerHour) {\n currentCount += 1;\n log(`Rate limit reached: ${currentCount} events in this hour`);\n }\n return true;\n }\n\n currentCount += 1;\n return false;\n };\n}\n\nconst url = getEnvelopeEndpointWithUrlEncodedAuth(dsn, tunnel, sdkMetadata.sdk);\nconst transport = makeNodeTransport({\n url,\n recordDroppedEvent: () => {\n //\n },\n});\nconst isRateLimited = createRateLimiter(maxEventsPerHour);\n\nasync function sendAbnormalSession(serializedSession: Session | undefined): Promise<void> {\n if (!serializedSession) {\n return;\n }\n\n log('Sending abnormal session');\n const session = makeSession(serializedSession);\n\n updateSession(session, {\n status: 'abnormal',\n abnormal_mechanism: 'anr_foreground',\n release,\n environment,\n });\n\n const envelope = createSessionEnvelope(session, dsn, sdkMetadata, tunnel);\n // Log the envelope so to aid in testing\n log(JSON.stringify(envelope));\n\n await transport.send(envelope);\n}\n\nlog('Started');\n\nfunction prepareStackFrames(stackFrames: StackFrame[] | undefined): StackFrame[] | undefined {\n if (!stackFrames) {\n return undefined;\n }\n\n // Strip Sentry frames and reverse the stack frames so they are in the correct order\n const strippedFrames = stripSentryFramesAndReverse(stackFrames);\n\n for (const frame of strippedFrames) {\n if (!frame.filename) {\n continue;\n }\n\n frame.in_app = filenameIsInApp(frame.filename);\n\n // If we have an app root path, rewrite the filenames to be relative to the app root\n if (appRootPath) {\n frame.filename = normalizeUrlToBase(frame.filename, appRootPath);\n }\n }\n\n return strippedFrames;\n}\n\nfunction stripFileProtocol(filename: string | undefined): string | undefined {\n if (!filename) {\n return undefined;\n }\n return filename.replace(/^file:\\/\\//, '');\n}\n\n// eslint-disable-next-line complexity\nfunction applyDebugMeta(event: Event, debugImages: Record<string, string>): void {\n if (Object.keys(debugImages).length === 0) {\n return;\n }\n\n const normalisedDebugImages = appRootPath ? {} : debugImages;\n if (appRootPath) {\n for (const [path, debugId] of Object.entries(debugImages)) {\n normalisedDebugImages[normalizeUrlToBase(path, appRootPath)] = debugId;\n }\n }\n\n const filenameToDebugId = new Map<string, string>();\n\n for (const exception of event.exception?.values || []) {\n for (const frame of exception.stacktrace?.frames || []) {\n const filename = stripFileProtocol(frame.abs_path || frame.filename);\n if (filename && normalisedDebugImages[filename]) {\n filenameToDebugId.set(filename, normalisedDebugImages[filename]);\n }\n }\n }\n\n for (const thread of event.threads?.values || []) {\n for (const frame of thread.stacktrace?.frames || []) {\n const filename = stripFileProtocol(frame.abs_path || frame.filename);\n if (filename && normalisedDebugImages[filename]) {\n filenameToDebugId.set(filename, normalisedDebugImages[filename]);\n }\n }\n }\n\n if (filenameToDebugId.size > 0) {\n const images: DebugImage[] = [];\n for (const [code_file, debug_id] of filenameToDebugId.entries()) {\n images.push({\n type: 'sourcemap',\n code_file,\n debug_id,\n });\n }\n event.debug_meta = { images };\n }\n}\n\nfunction getExceptionAndThreads(\n crashedThreadId: string,\n threads: ReturnType<typeof captureStackTrace<CurrentScopes, ThreadState>>,\n): Event {\n const crashedThread = threads[crashedThreadId];\n\n return {\n exception: {\n values: [\n {\n type: 'EventLoopBlocked',\n value: `Event Loop Blocked for at least ${threshold} ms`,\n stacktrace: { frames: prepareStackFrames(crashedThread?.frames) },\n // This ensures the UI doesn't say 'Crashed in' for the stack trace\n mechanism: { type: 'ANR' },\n thread_id: crashedThreadId,\n },\n ],\n },\n threads: {\n values: Object.entries(threads).map(([threadId, threadState]) => {\n const crashed = threadId === crashedThreadId;\n\n const thread: Thread = {\n id: threadId,\n name: threadId === '0' ? 'main' : `worker-${threadId}`,\n crashed,\n current: true,\n main: threadId === '0',\n };\n\n if (!crashed) {\n thread.stacktrace = { frames: prepareStackFrames(threadState.frames) };\n }\n\n return thread;\n }),\n },\n };\n}\n\nfunction applyScopeToEvent(event: Event, scope: ScopeData): void {\n applyScopeDataToEvent(event, scope);\n\n if (!event.contexts?.trace) {\n const { traceId, parentSpanId, propagationSpanId } = scope.propagationContext;\n event.contexts = {\n trace: {\n trace_id: traceId,\n span_id: propagationSpanId || generateSpanId(),\n parent_span_id: parentSpanId,\n },\n ...event.contexts,\n };\n }\n}\n\nasync function sendBlockEvent(crashedThreadId: string): Promise<void> {\n if (isRateLimited()) {\n return;\n }\n\n const threads = captureStackTrace<CurrentScopes, ThreadState>();\n const crashedThread = threads[crashedThreadId];\n\n if (!crashedThread) {\n log(`No thread found with ID '${crashedThreadId}'`);\n return;\n }\n\n try {\n await sendAbnormalSession(crashedThread.pollState?.session);\n } catch (error) {\n log(`Failed to send abnormal session for thread '${crashedThreadId}':`, error);\n }\n\n log('Sending event');\n\n const event: Event = {\n event_id: uuid4(),\n contexts,\n release,\n environment,\n dist,\n platform: 'node',\n level: 'error',\n tags,\n ...getExceptionAndThreads(crashedThreadId, threads),\n };\n\n const scope = crashedThread.pollState?.scope\n ? new Scope().update(crashedThread.pollState.scope).getScopeData()\n : new Scope().getScopeData();\n\n if (crashedThread?.asyncState?.isolationScope) {\n // We need to rehydrate the scope from the serialized object with properties beginning with _user, etc\n const isolationScope = Object.assign(new Scope(), crashedThread.asyncState.isolationScope).getScopeData();\n mergeScopeData(scope, isolationScope);\n }\n applyScopeToEvent(event, scope);\n\n const allDebugImages: Record<string, string> = Object.values(threads).reduce((acc, threadState) => {\n return { ...acc, ...threadState.pollState?.debugImages };\n }, {});\n\n applyDebugMeta(event, allDebugImages);\n\n const envelope = createEventEnvelope(event, dsn, sdkMetadata, tunnel);\n // Log the envelope to aid in testing\n log(JSON.stringify(envelope));\n\n await transport.send(envelope);\n await transport.flush(2000);\n}\n\nsetInterval(async () => {\n for (const [threadId, time] of Object.entries(getThreadsLastSeen())) {\n if (time > threshold) {\n if (triggeredThreads.has(threadId)) {\n continue;\n }\n\n log(`Blocked thread detected '${threadId}' last polled ${time} ms ago.`);\n triggeredThreads.add(threadId);\n\n try {\n await sendBlockEvent(threadId);\n } catch (error) {\n log(`Failed to send event for thread '${threadId}':`, error);\n }\n } else {\n triggeredThreads.delete(threadId);\n }\n }\n}, pollInterval);\n"],"names":["maxEventsPerHour","isRateLimited"],"mappings":"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"}

@@ -1,1 +0,1 @@

{"type":"module","version":"10.57.0","sideEffects":false}
{"type":"module","version":"10.58.0","sideEffects":false}
{
"name": "@sentry/node-native",
"version": "10.57.0",
"version": "10.58.0",
"description": "Native Tools for the Official Sentry Node.js SDK",

@@ -65,5 +65,5 @@ "repository": "git://github.com/getsentry/sentry-javascript.git",

"dependencies": {
"@sentry-internal/node-native-stacktrace": "^0.5.0",
"@sentry/core": "10.57.0",
"@sentry/node": "10.57.0"
"@sentry/node-native-stacktrace": "^0.5.1",
"@sentry/core": "10.58.0",
"@sentry/node": "10.58.0"
},

@@ -70,0 +70,0 @@ "devDependencies": {