{"version":3,"file":"initOtel.js","sources":["../../../src/sdk/initOtel.ts"],"sourcesContent":["import type { TracerProvider } from '@opentelemetry/api';\nimport { context, propagation, trace } from '@opentelemetry/api';\nimport type { SpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { BasicTracerProvider } from '@opentelemetry/sdk-trace-base';\nimport { debug as coreDebug, hasSpanStreamingEnabled } from '@sentry/core';\nimport {\n initializeEsmLoader,\n type NodeClient,\n SentryContextManager,\n setupOpenTelemetryLogger,\n} from '@sentry/node-core';\nimport {\n applyOtelSpanData,\n type AsyncLocalStorageLookup,\n backfillStreamedSpanDataFromOtel,\n getSentryResource,\n type OpenTelemetryTracerProvider,\n SentryPropagator,\n SentrySampler,\n SentrySpanProcessor,\n SentryTracerProvider,\n setIsSetup,\n} from '@sentry/opentelemetry';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { getOpenTelemetryInstrumentationToPreload } from '../integrations/tracing';\n\n// About 277h - this must fit into new Array(len)!\nconst MAX_MAX_SPAN_WAIT_DURATION = 1_000_000;\n\n// The global registry of @opentelemetry/api 1.x, shared across all copies of the package\nconst OTEL_API_GLOBAL_KEY = Symbol.for('opentelemetry.js.api.1');\n\n/**\n * Registers the given tracer provider as the global tracer provider, recreating the OpenTelemetry\n * API registry when it pre-exists with a different `@opentelemetry/api` version.\n *\n * Some host runtimes (e.g. Neon Functions) pre-create the registry with their own API version.\n * `registerGlobal` requires an exact version match, so every registration through the SDK's copy\n * of `@opentelemetry/api` is rejected and tracing is silently disabled\n * (https://github.com/getsentry/sentry-javascript/issues/22338). This case is identified by a\n * failed registration with an empty `trace` slot: `registerGlobal` checks the slot before the\n * version, so an empty slot means the version gate rejected us and recreating the registry\n * clobbers no other tracer provider. If the slot is occupied (another provider registered first,\n * e.g. a second `Sentry.init()` call), the registry is left untouched and registration fails.\n *\n * Slots Sentry does not claim itself (e.g. `diag`, `metrics`) are carried over into the recreated\n * registry: reads resolve via a semver-compatibility check rather than the exact-match write gate,\n * so they keep working for the copy that registered them. `propagation` and `context` are not\n * carried over because Sentry registers its own right after this.\n */\nfunction registerGlobalTracerProvider(provider: TracerProvider): boolean {\n if (trace.setGlobalTracerProvider(provider)) {\n return true;\n }\n\n // @opentelemetry/api stores the registry under a `Symbol.for` key that no public type\n // describes, so `typeof globalThis` can only be narrowed to it by casting through `unknown`.\n const otelGlobal = globalThis as unknown as Record | undefined>;\n const registry = otelGlobal[OTEL_API_GLOBAL_KEY];\n if (registry && !registry.trace) {\n DEBUG_BUILD &&\n coreDebug.warn(\n 'Replaced a pre-existing OpenTelemetry API registry that was created by a different @opentelemetry/api version and would have blocked tracing. If you want to manage OpenTelemetry yourself, set `skipOpenTelemetrySetup: true` in `Sentry.init()`.',\n );\n otelGlobal[OTEL_API_GLOBAL_KEY] = undefined;\n\n if (!trace.setGlobalTracerProvider(provider)) {\n return false;\n }\n\n // The cast is needed because TS still has the slot narrowed to `undefined` from the reset\n // above and cannot know the registration call just recreated the registry.\n const recreatedRegistry = otelGlobal[OTEL_API_GLOBAL_KEY] as Record | undefined;\n if (recreatedRegistry) {\n const { propagation: _propagation, context: _context, ...carriedOverSlots } = registry;\n otelGlobal[OTEL_API_GLOBAL_KEY] = { ...carriedOverSlots, ...recreatedRegistry };\n }\n\n return true;\n }\n\n return false;\n}\n\ninterface AdditionalOpenTelemetryOptions {\n /** Additional SpanProcessor instances that should be used. */\n spanProcessors?: SpanProcessor[];\n}\n\n/**\n * Initialize OpenTelemetry for Node.\n */\nexport function initOpenTelemetry(client: NodeClient, options: AdditionalOpenTelemetryOptions = {}): void {\n if (client.getOptions().debug) {\n setupOpenTelemetryLogger();\n }\n\n const [provider, asyncLocalStorageLookup] = setupOtel(client, options);\n client.traceProvider = provider;\n client.asyncLocalStorageLookup = asyncLocalStorageLookup;\n}\n\ninterface NodePreloadOptions {\n debug?: boolean;\n integrations?: string[];\n}\n\n/**\n * Preload OpenTelemetry for Node.\n * This can be used to preload instrumentation early, but set up Sentry later.\n * By preloading the OTEL instrumentation wrapping still happens early enough that everything works.\n */\nexport function preloadOpenTelemetry(options: NodePreloadOptions = {}): void {\n const { debug } = options;\n\n if (debug) {\n coreDebug.enable();\n }\n\n initializeEsmLoader();\n\n // These are all integrations that we need to pre-load to ensure they are set up before any other code runs\n getPreloadMethods(options.integrations).forEach(fn => {\n fn();\n\n if (debug) {\n coreDebug.log(`[Sentry] Preloaded ${fn.id} instrumentation`);\n }\n });\n}\n\nfunction getPreloadMethods(integrationNames?: string[]): ((() => void) & { id: string })[] {\n const instruments = getOpenTelemetryInstrumentationToPreload();\n\n if (!integrationNames) {\n return instruments;\n }\n\n // We match exact matches of instrumentation, but also match prefixes, e.g. \"Fastify.v5\" will match \"Fastify\"\n return instruments.filter(instrumentation => {\n const id = instrumentation.id;\n return integrationNames.some(integrationName => id === integrationName || id.startsWith(`${integrationName}.`));\n });\n}\n\n/** Just exported for tests. */\nexport function setupOtel(\n client: NodeClient,\n options: AdditionalOpenTelemetryOptions = {},\n): [OpenTelemetryTracerProvider | undefined, AsyncLocalStorageLookup | undefined] {\n // Sentry's minimal tracer provider is the default. We fall back to the full OpenTelemetry SDK\n // `BasicTracerProvider` when the user explicitly opts in via `openTelemetryBasicTracerProvider`, or\n // when they provide custom `openTelemetrySpanProcessors` — those require the SDK span pipeline\n // that the minimal provider does not run.\n const shouldUseBasicTracerProvider =\n client.getOptions().openTelemetryBasicTracerProvider || !!options.spanProcessors?.length;\n\n if (!shouldUseBasicTracerProvider) {\n return setupSentryTracerProvider(client);\n }\n\n // Create and configure NodeTracerProvider\n const provider = new BasicTracerProvider({\n sampler: new SentrySampler(client),\n resource: getSentryResource('node'),\n forceFlushTimeoutMillis: 500,\n spanProcessors: [\n new SentrySpanProcessor({\n timeout: _clampSpanProcessorTimeout(client.getOptions().maxSpanWaitDuration),\n client,\n }),\n ...(options.spanProcessors || []),\n ],\n });\n\n // Register as globals\n registerGlobalTracerProvider(provider);\n propagation.setGlobalPropagator(new SentryPropagator());\n\n const ctxManager = new SentryContextManager();\n context.setGlobalContextManager(ctxManager);\n\n return [provider, ctxManager.getAsyncLocalStorageLookup()];\n}\n\nfunction setupSentryTracerProvider(\n client: NodeClient,\n): [SentryTracerProvider | undefined, AsyncLocalStorageLookup | undefined] {\n const provider = new SentryTracerProvider({ resource: getSentryResource('node') });\n\n if (!registerGlobalTracerProvider(provider)) {\n DEBUG_BUILD &&\n coreDebug.warn(\n 'Could not register SentryTracerProvider because another OpenTelemetry tracer provider is already registered.',\n );\n return [undefined, undefined];\n }\n\n // Only mark the provider as set up once it is actually the registered global\n // tracer provider, so setup validation doesn't skip required checks when\n // registration failed.\n setIsSetup('SentryTracerProvider');\n\n propagation.setGlobalPropagator(new SentryPropagator());\n\n const ctxManager = new SentryContextManager();\n context.setGlobalContextManager(ctxManager);\n\n client.on('spanEnd', span => {\n applyOtelSpanData(span, { finalizeStatus: true });\n });\n\n if (hasSpanStreamingEnabled(client)) {\n // Streamed spans skip the exporter, so per-span data inferred from OTel semantic conventions\n // (notably `sentry.source` on child spans, which `applyOtelSpanData` only sets on segment roots)\n // is backfilled here, reusing the exact inference the OTel SDK `SentrySpanProcessor` applies.\n client.on('preprocessSpan', backfillStreamedSpanDataFromOtel);\n }\n\n client.on('preprocessEvent', event => {\n if (event.type !== 'transaction') {\n return;\n }\n\n event.contexts = {\n ...event.contexts,\n otel: {\n resource: provider.resource?.attributes,\n ...event.contexts?.otel,\n },\n };\n });\n\n return [provider, ctxManager.getAsyncLocalStorageLookup()];\n}\n\n/** Just exported for tests. */\nexport function _clampSpanProcessorTimeout(maxSpanWaitDuration: number | undefined): number | undefined {\n if (maxSpanWaitDuration == null) {\n return undefined;\n }\n\n // We guard for a max. value here, because we create an array with this length\n // So if this value is too large, this would fail\n if (maxSpanWaitDuration > MAX_MAX_SPAN_WAIT_DURATION) {\n DEBUG_BUILD &&\n coreDebug.warn(`\\`maxSpanWaitDuration\\` is too high, using the maximum value of ${MAX_MAX_SPAN_WAIT_DURATION}`);\n return MAX_MAX_SPAN_WAIT_DURATION;\n } else if (maxSpanWaitDuration <= 0 || Number.isNaN(maxSpanWaitDuration)) {\n DEBUG_BUILD && coreDebug.warn('`maxSpanWaitDuration` must be a positive number, using default value instead.');\n return undefined;\n }\n\n return maxSpanWaitDuration;\n}\n"],"names":["trace","DEBUG_BUILD","coreDebug","setupOpenTelemetryLogger","initializeEsmLoader","getOpenTelemetryInstrumentationToPreload","BasicTracerProvider","SentrySampler","getSentryResource","SentrySpanProcessor","propagation","SentryPropagator","SentryContextManager","context","SentryTracerProvider","setIsSetup","applyOtelSpanData","hasSpanStreamingEnabled","backfillStreamedSpanDataFromOtel"],"mappings":"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"}