{"version":3,"file":"index.js","sources":["../../src/asyncLocalStorageContextManager.ts","../../src/nodeAsyncContextStrategy.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTICE from the Sentry authors:\n * This implementation follows the behavior of OpenTelemetry’s `@opentelemetry/context-async-hooks`\n * package, combining logic that upstream splits across:\n * - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AbstractAsyncHooksContextManager.ts\n * - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AsyncLocalStorageContextManager.ts\n * It is a single-class re-implementation for Sentry (not a verbatim copy of those files).\n */\n\nimport type { Context, ContextManager } from '@opentelemetry/api';\nimport { ROOT_CONTEXT } from '@opentelemetry/api';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { EventEmitter } from 'node:events';\nimport type { AsyncLocalStorageLookup } from './contextManager';\nimport { SENTRY_SCOPES_CONTEXT_KEY } from './constants';\nimport { buildContextWithSentryScopes } from './utils/buildContextWithSentryScopes';\nimport { setIsSetup } from './utils/setupCheck';\nimport { getAsyncContextStrategy, getMainCarrier } from '@sentry/core';\n\ntype ListenerFn = (...args: unknown[]) => unknown;\n\n/**\n * Per-event map from user listeners to context-bound listeners.\n */\ntype PatchMap = Record>;\n\nconst ADD_LISTENER_METHODS = ['addListener', 'on', 'once', 'prependListener', 'prependOnceListener'] as const;\n\n/**\n * OpenTelemetry-compatible context manager using Node.js `AsyncLocalStorage`.\n * Semantics match `@opentelemetry/context-async-hooks` (function `bind` + `EventEmitter` patching).\n */\nexport class SentryAsyncLocalStorageContextManager implements ContextManager {\n protected readonly _asyncLocalStorage: AsyncLocalStorage;\n\n private readonly _kOtListeners = Symbol('OtListeners');\n private _wrapped = false;\n\n public constructor() {\n setIsSetup('SentryContextManager');\n // Pick the instance from the async context strategy\n // this should normally always be there, but if it is not for whatever reason, we fall back to a new instance\n this._asyncLocalStorage =\n (getAsyncContextStrategy(getMainCarrier()).getTracingChannelBinding?.()\n ?.asyncLocalStorage as AsyncLocalStorage) ?? new AsyncLocalStorage();\n }\n\n public active(): Context {\n return this._asyncLocalStorage.getStore() ?? ROOT_CONTEXT;\n }\n\n public with ReturnType>(\n context: Context,\n fn: F,\n thisArg?: ThisParameterType,\n ...args: A\n ): ReturnType {\n const ctx2 = buildContextWithSentryScopes(context, this.active());\n const cb = thisArg == null ? fn : fn.bind(thisArg);\n return this._asyncLocalStorage.run(ctx2, cb as never, ...args);\n }\n\n public enable(): this {\n return this;\n }\n\n public disable(): this {\n this._asyncLocalStorage.disable();\n return this;\n }\n\n public bind(context: Context, target: T): T {\n if (target instanceof EventEmitter) {\n return this._bindEventEmitter(context, target);\n }\n if (typeof target === 'function') {\n return this._bindFunction(context, target as unknown as ListenerFn) as T;\n }\n return target;\n }\n\n /**\n * Gets underlying AsyncLocalStorage and symbol to allow lookup of scope.\n * This is Sentry-specific.\n */\n public getAsyncLocalStorageLookup(): AsyncLocalStorageLookup {\n return {\n asyncLocalStorage: this._asyncLocalStorage,\n contextSymbol: SENTRY_SCOPES_CONTEXT_KEY,\n };\n }\n\n private _bindFunction(context: Context, target: ListenerFn): ListenerFn {\n const managerWith = this.with.bind(this);\n const contextWrapper = function (this: never, ...args: unknown[]) {\n return managerWith(context, () => target.apply(this, args));\n };\n Object.defineProperty(contextWrapper, 'length', {\n enumerable: false,\n configurable: true,\n writable: false,\n value: target.length,\n });\n return contextWrapper;\n }\n\n private _bindEventEmitter(context: Context, ee: T): T {\n if (this._getPatchMap(ee) !== undefined) {\n return ee;\n }\n this._createPatchMap(ee);\n\n for (const methodName of ADD_LISTENER_METHODS) {\n if (ee[methodName] === undefined) continue;\n ee[methodName] = this._patchAddListener(\n ee,\n ee[methodName] as unknown as (...args: unknown[]) => unknown,\n context,\n );\n }\n if (typeof ee.removeListener === 'function') {\n // oxlint-disable-next-line @typescript-eslint/unbound-method -- patched like upstream OTel context manager\n ee.removeListener = this._patchRemoveListener(ee, ee.removeListener as (...args: unknown[]) => unknown);\n }\n if (typeof ee.off === 'function') {\n // oxlint-disable-next-line @typescript-eslint/unbound-method\n ee.off = this._patchRemoveListener(ee, ee.off as (...args: unknown[]) => unknown);\n }\n if (typeof ee.removeAllListeners === 'function') {\n ee.removeAllListeners = this._patchRemoveAllListeners(\n ee,\n // oxlint-disable-next-line @typescript-eslint/unbound-method\n ee.removeAllListeners as (...args: unknown[]) => unknown,\n );\n }\n return ee;\n }\n\n private _patchRemoveListener(ee: EventEmitter, original: (...args: unknown[]) => unknown) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event: string, listener: ListenerFn) {\n const events = contextManager._getPatchMap(ee)?.[event];\n if (events === undefined) {\n return original.call(this, event, listener);\n }\n const patchedListener = events.get(listener);\n return original.call(this, event, patchedListener || listener);\n };\n }\n\n private _patchRemoveAllListeners(ee: EventEmitter, original: (...args: unknown[]) => unknown) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event?: string) {\n const map = contextManager._getPatchMap(ee);\n if (map !== undefined) {\n if (arguments.length === 0) {\n contextManager._createPatchMap(ee);\n } else if (event !== undefined && map[event] !== undefined) {\n // oxlint-disable-next-line @typescript-eslint/no-dynamic-delete -- event-keyed listener map\n delete map[event];\n }\n }\n return original.apply(this, arguments);\n };\n }\n\n private _patchAddListener(ee: EventEmitter, original: (...args: unknown[]) => unknown, context: Context) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event: string, listener: ListenerFn) {\n if (contextManager._wrapped) {\n return original.call(this, event, listener);\n }\n let map = contextManager._getPatchMap(ee);\n if (map === undefined) {\n map = contextManager._createPatchMap(ee);\n }\n let listeners = map[event];\n if (listeners === undefined) {\n listeners = new WeakMap();\n map[event] = listeners;\n }\n const patchedListener = contextManager.bind(context, listener);\n listeners.set(listener, patchedListener);\n\n contextManager._wrapped = true;\n try {\n return original.call(this, event, patchedListener);\n } finally {\n contextManager._wrapped = false;\n }\n };\n }\n\n private _createPatchMap(ee: EventEmitter): PatchMap {\n const map = Object.create(null) as PatchMap;\n (ee as unknown as Record)[this._kOtListeners] = map;\n return map;\n }\n\n private _getPatchMap(ee: EventEmitter): PatchMap | undefined {\n return (ee as unknown as Record)[this._kOtListeners];\n }\n}\n","import * as api from '@opentelemetry/api';\nimport { setOpenTelemetryContextAsyncContextStrategy } from './asyncContextStrategy';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { getRootSpan, spanIsIgnored, type TracingChannelBinding } from '@sentry/core';\nimport { SENTRY_TRACE_STATE_CHILD_IGNORED } from './constants';\n\ninterface ContextApi {\n _getContextManager():\n | undefined\n | {\n getAsyncLocalStorageLookup(): {\n asyncLocalStorage: unknown;\n };\n };\n}\n\nexport function setNodeOpenTelemetryContextAsyncContextStrategy(options?: { skipOpenTelemetrySetup?: boolean }): void {\n setOpenTelemetryContextAsyncContextStrategy({\n getTracingChannelBinding: !options?.skipOpenTelemetrySetup\n ? getDefaultAsyncLocalStorageFactory()\n : getCustomAsyncLocalStorageFactory(),\n });\n}\n\n/**\n * In the default case, we build the local storage instance ourselves here.\n * The default asyncLocalStorageContextManager will then use this internally.\n */\nfunction getDefaultAsyncLocalStorageFactory(): () => TracingChannelBinding {\n const defaultAsyncLocalStorage = new AsyncLocalStorage();\n\n return () => {\n return {\n asyncLocalStorage: defaultAsyncLocalStorage,\n getStoreWithActiveSpan,\n } satisfies TracingChannelBinding;\n };\n}\n\n/**\n * If we have a custom context manager, we need to access it via the context manager\n * this may not be available yet, if this is called before the Otel ContextManager was setup\n * in this case, we need to return undefined and retry later, hoping that the setup works by then\n */\nfunction getCustomAsyncLocalStorageFactory(): () => TracingChannelBinding | undefined {\n return () => {\n try {\n const contextManager = (api.context as unknown as ContextApi)._getContextManager();\n const asyncLocalStorage = contextManager?.getAsyncLocalStorageLookup().asyncLocalStorage;\n\n return asyncLocalStorage\n ? ({\n asyncLocalStorage,\n getStoreWithActiveSpan,\n } satisfies TracingChannelBinding)\n : undefined;\n } catch {\n return undefined;\n }\n };\n}\n\nfunction getStoreWithActiveSpan(span: Parameters[0]): api.Context {\n const activeContext = api.context.active();\n\n // Tracing channels bind directly to the context manager's AsyncLocalStorage and bypass\n // SentryContextManager.with(), so ignored children must restore their parent here as well.\n const isIgnoredChild =\n (spanIsIgnored(span) && getRootSpan(span) !== span) ||\n span.spanContext().traceState?.get(SENTRY_TRACE_STATE_CHILD_IGNORED) === '1';\n\n return isIgnoredChild ? activeContext : api.trace.setSpan(activeContext, span);\n}\n"],"names":[],"mappings":"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"}