@sentry/node 10.50.0-alpha.0 → 10.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/build/cjs/index.js +7 -7
  2. package/build/cjs/integrations/{node-fetch.js → node-fetch/index.js} +3 -3
  3. package/build/cjs/integrations/node-fetch/index.js.map +1 -0
  4. package/build/cjs/integrations/node-fetch/vendored/undici.js +484 -0
  5. package/build/cjs/integrations/node-fetch/vendored/undici.js.map +1 -0
  6. package/build/cjs/sdk/index.js +2 -2
  7. package/build/cjs/sdk/index.js.map +1 -1
  8. package/build/esm/index.js +3 -3
  9. package/build/esm/integrations/{node-fetch.js → node-fetch/index.js} +2 -2
  10. package/build/esm/integrations/node-fetch/index.js.map +1 -0
  11. package/build/esm/integrations/node-fetch/vendored/undici.js +482 -0
  12. package/build/esm/integrations/node-fetch/vendored/undici.js.map +1 -0
  13. package/build/esm/package.json +1 -1
  14. package/build/esm/sdk/index.js +1 -1
  15. package/build/types/index.d.ts +2 -2
  16. package/build/types/index.d.ts.map +1 -1
  17. package/build/types/integrations/{node-fetch.d.ts → node-fetch/index.d.ts} +2 -2
  18. package/build/types/integrations/node-fetch/index.d.ts.map +1 -0
  19. package/build/types/integrations/node-fetch/vendored/internal-types.d.ts +25 -0
  20. package/build/types/integrations/node-fetch/vendored/internal-types.d.ts.map +1 -0
  21. package/build/types/integrations/node-fetch/vendored/types.d.ts +62 -0
  22. package/build/types/integrations/node-fetch/vendored/types.d.ts.map +1 -0
  23. package/build/types/integrations/node-fetch/vendored/undici.d.ts +22 -0
  24. package/build/types/integrations/node-fetch/vendored/undici.d.ts.map +1 -0
  25. package/build/types-ts3.8/index.d.ts +2 -2
  26. package/build/types-ts3.8/integrations/{node-fetch.d.ts → node-fetch/index.d.ts} +2 -2
  27. package/build/types-ts3.8/integrations/node-fetch/vendored/internal-types.d.ts +25 -0
  28. package/build/types-ts3.8/integrations/node-fetch/vendored/types.d.ts +62 -0
  29. package/build/types-ts3.8/integrations/node-fetch/vendored/undici.d.ts +22 -0
  30. package/package.json +4 -5
  31. package/build/cjs/integrations/node-fetch.js.map +0 -1
  32. package/build/esm/integrations/node-fetch.js.map +0 -1
  33. package/build/types/integrations/node-fetch.d.ts.map +0 -1
@@ -3,7 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
3
  const core = require('@sentry/core');
4
4
  const nodeCore = require('@sentry/node-core');
5
5
  const http = require('../integrations/http.js');
6
- const nodeFetch = require('../integrations/node-fetch.js');
6
+ const index$1 = require('../integrations/node-fetch/index.js');
7
7
  const index = require('../integrations/tracing/index.js');
8
8
  const initOtel = require('./initOtel.js');
9
9
 
@@ -16,7 +16,7 @@ function getDefaultIntegrationsWithoutPerformance() {
16
16
  // Filter out the node-core HTTP and NodeFetch integrations and replace them with Node SDK's composite versions
17
17
  return nodeCoreIntegrations
18
18
  .filter(integration => integration.name !== 'Http' && integration.name !== 'NodeFetch')
19
- .concat(http.httpIntegration(), nodeFetch.nativeNodeFetchIntegration());
19
+ .concat(http.httpIntegration(), index$1.nativeNodeFetchIntegration());
20
20
  }
21
21
 
22
22
  /** Get the default integrations for the Node SDK. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/sdk/index.ts"],"sourcesContent":["import type { Integration, Options } from '@sentry/core';\nimport { applySdkMetadata, hasSpansEnabled } from '@sentry/core';\nimport type { NodeClient } from '@sentry/node-core';\nimport {\n getDefaultIntegrations as getNodeCoreDefaultIntegrations,\n init as initNodeCore,\n validateOpenTelemetrySetup,\n} from '@sentry/node-core';\nimport { httpIntegration } from '../integrations/http';\nimport { nativeNodeFetchIntegration } from '../integrations/node-fetch';\nimport { getAutoPerformanceIntegrations } from '../integrations/tracing';\nimport type { NodeOptions } from '../types';\nimport { initOpenTelemetry } from './initOtel';\n\n/**\n * Get default integrations, excluding performance.\n */\nexport function getDefaultIntegrationsWithoutPerformance(): Integration[] {\n const nodeCoreIntegrations = getNodeCoreDefaultIntegrations();\n\n // Filter out the node-core HTTP and NodeFetch integrations and replace them with Node SDK's composite versions\n return nodeCoreIntegrations\n .filter(integration => integration.name !== 'Http' && integration.name !== 'NodeFetch')\n .concat(httpIntegration(), nativeNodeFetchIntegration());\n}\n\n/** Get the default integrations for the Node SDK. */\nexport function getDefaultIntegrations(options: Options): Integration[] {\n return [\n ...getDefaultIntegrationsWithoutPerformance(),\n // We only add performance integrations if tracing is enabled\n // Note that this means that without tracing enabled, e.g. `expressIntegration()` will not be added\n // This means that generally request isolation will work (because that is done by httpIntegration)\n // But `transactionName` will not be set automatically\n ...(hasSpansEnabled(options) ? getAutoPerformanceIntegrations() : []),\n ];\n}\n\n/**\n * Initialize Sentry for Node.\n */\nexport function init(options: NodeOptions | undefined = {}): NodeClient | undefined {\n return _init(options, getDefaultIntegrations);\n}\n\n/**\n * Internal initialization function.\n */\nfunction _init(\n options: NodeOptions | undefined = {},\n getDefaultIntegrationsImpl: (options: Options) => Integration[],\n): NodeClient | undefined {\n applySdkMetadata(options, 'node');\n\n const client = initNodeCore({\n ...options,\n // Only use Node SDK defaults if none provided\n defaultIntegrations: options.defaultIntegrations ?? getDefaultIntegrationsImpl(options),\n });\n\n // Add Node SDK specific OpenTelemetry setup\n if (client && !options.skipOpenTelemetrySetup) {\n initOpenTelemetry(client, {\n spanProcessors: options.openTelemetrySpanProcessors,\n });\n validateOpenTelemetrySetup();\n }\n\n return client;\n}\n\n/**\n * Initialize Sentry for Node, without any integrations added by default.\n */\nexport function initWithoutDefaultIntegrations(options: NodeOptions | undefined = {}): NodeClient | undefined {\n return _init(options, () => []);\n}\n"],"names":["getNodeCoreDefaultIntegrations","httpIntegration","nativeNodeFetchIntegration","hasSpansEnabled","getAutoPerformanceIntegrations","applySdkMetadata","initNodeCore","initOpenTelemetry","validateOpenTelemetrySetup"],"mappings":";;;;;;;;;AAcA;AACA;AACA;AACO,SAAS,wCAAwC,GAAkB;AAC1E,EAAE,MAAM,oBAAA,GAAuBA,+BAA8B,EAAE;;AAE/D;AACA,EAAE,OAAO;AACT,KAAK,MAAM,CAAC,WAAA,IAAe,WAAW,CAAC,IAAA,KAAS,UAAU,WAAW,CAAC,IAAA,KAAS,WAAW;AAC1F,KAAK,MAAM,CAACC,oBAAe,EAAE,EAAEC,oCAA0B,EAAE,CAAC;AAC5D;;AAEA;AACO,SAAS,sBAAsB,CAAC,OAAO,EAA0B;AACxE,EAAE,OAAO;AACT,IAAI,GAAG,wCAAwC,EAAE;AACjD;AACA;AACA;AACA;AACA,IAAI,IAAIC,oBAAe,CAAC,OAAO,CAAA,GAAIC,oCAA8B,EAAC,GAAI,EAAE,CAAC;AACzE,GAAG;AACH;;AAEA;AACA;AACA;AACO,SAAS,IAAI,CAAC,OAAO,GAA4B,EAAE,EAA0B;AACpF,EAAE,OAAO,KAAK,CAAC,OAAO,EAAE,sBAAsB,CAAC;AAC/C;;AAEA;AACA;AACA;AACA,SAAS,KAAK;AACd,EAAE,OAAO,GAA4B,EAAE;AACvC,EAAE,0BAA0B;AAC5B,EAA0B;AAC1B,EAAEC,qBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC;;AAEnC,EAAE,MAAM,MAAA,GAASC,aAAY,CAAC;AAC9B,IAAI,GAAG,OAAO;AACd;AACA,IAAI,mBAAmB,EAAE,OAAO,CAAC,uBAAuB,0BAA0B,CAAC,OAAO,CAAC;AAC3F,GAAG,CAAC;;AAEJ;AACA,EAAE,IAAI,MAAA,IAAU,CAAC,OAAO,CAAC,sBAAsB,EAAE;AACjD,IAAIC,0BAAiB,CAAC,MAAM,EAAE;AAC9B,MAAM,cAAc,EAAE,OAAO,CAAC,2BAA2B;AACzD,KAAK,CAAC;AACN,IAAIC,mCAA0B,EAAE;AAChC,EAAE;;AAEF,EAAE,OAAO,MAAM;AACf;;AAEA;AACA;AACA;AACO,SAAS,8BAA8B,CAAC,OAAO,GAA4B,EAAE,EAA0B;AAC9G,EAAE,OAAO,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;AACjC;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/sdk/index.ts"],"sourcesContent":["import type { Integration, Options } from '@sentry/core';\nimport { applySdkMetadata, hasSpansEnabled } from '@sentry/core';\nimport type { NodeClient } from '@sentry/node-core';\nimport {\n getDefaultIntegrations as getNodeCoreDefaultIntegrations,\n init as initNodeCore,\n validateOpenTelemetrySetup,\n} from '@sentry/node-core';\nimport { httpIntegration } from '../integrations/http';\nimport { nativeNodeFetchIntegration } from '../integrations/node-fetch';\nimport { getAutoPerformanceIntegrations } from '../integrations/tracing';\nimport type { NodeOptions } from '../types';\nimport { initOpenTelemetry } from './initOtel';\n\n/**\n * Get default integrations, excluding performance.\n */\nexport function getDefaultIntegrationsWithoutPerformance(): Integration[] {\n const nodeCoreIntegrations = getNodeCoreDefaultIntegrations();\n\n // Filter out the node-core HTTP and NodeFetch integrations and replace them with Node SDK's composite versions\n return nodeCoreIntegrations\n .filter(integration => integration.name !== 'Http' && integration.name !== 'NodeFetch')\n .concat(httpIntegration(), nativeNodeFetchIntegration());\n}\n\n/** Get the default integrations for the Node SDK. */\nexport function getDefaultIntegrations(options: Options): Integration[] {\n return [\n ...getDefaultIntegrationsWithoutPerformance(),\n // We only add performance integrations if tracing is enabled\n // Note that this means that without tracing enabled, e.g. `expressIntegration()` will not be added\n // This means that generally request isolation will work (because that is done by httpIntegration)\n // But `transactionName` will not be set automatically\n ...(hasSpansEnabled(options) ? getAutoPerformanceIntegrations() : []),\n ];\n}\n\n/**\n * Initialize Sentry for Node.\n */\nexport function init(options: NodeOptions | undefined = {}): NodeClient | undefined {\n return _init(options, getDefaultIntegrations);\n}\n\n/**\n * Internal initialization function.\n */\nfunction _init(\n options: NodeOptions | undefined = {},\n getDefaultIntegrationsImpl: (options: Options) => Integration[],\n): NodeClient | undefined {\n applySdkMetadata(options, 'node');\n\n const client = initNodeCore({\n ...options,\n // Only use Node SDK defaults if none provided\n defaultIntegrations: options.defaultIntegrations ?? getDefaultIntegrationsImpl(options),\n });\n\n // Add Node SDK specific OpenTelemetry setup\n if (client && !options.skipOpenTelemetrySetup) {\n initOpenTelemetry(client, {\n spanProcessors: options.openTelemetrySpanProcessors,\n });\n validateOpenTelemetrySetup();\n }\n\n return client;\n}\n\n/**\n * Initialize Sentry for Node, without any integrations added by default.\n */\nexport function initWithoutDefaultIntegrations(options: NodeOptions | undefined = {}): NodeClient | undefined {\n return _init(options, () => []);\n}\n"],"names":["getNodeCoreDefaultIntegrations","httpIntegration","nativeNodeFetchIntegration","hasSpansEnabled","getAutoPerformanceIntegrations","applySdkMetadata","initNodeCore","initOpenTelemetry","validateOpenTelemetrySetup"],"mappings":";;;;;;;;;AAcA;AACA;AACA;AACO,SAAS,wCAAwC,GAAkB;AAC1E,EAAE,MAAM,oBAAA,GAAuBA,+BAA8B,EAAE;;AAE/D;AACA,EAAE,OAAO;AACT,KAAK,MAAM,CAAC,WAAA,IAAe,WAAW,CAAC,IAAA,KAAS,UAAU,WAAW,CAAC,IAAA,KAAS,WAAW;AAC1F,KAAK,MAAM,CAACC,oBAAe,EAAE,EAAEC,kCAA0B,EAAE,CAAC;AAC5D;;AAEA;AACO,SAAS,sBAAsB,CAAC,OAAO,EAA0B;AACxE,EAAE,OAAO;AACT,IAAI,GAAG,wCAAwC,EAAE;AACjD;AACA;AACA;AACA;AACA,IAAI,IAAIC,oBAAe,CAAC,OAAO,CAAA,GAAIC,oCAA8B,EAAC,GAAI,EAAE,CAAC;AACzE,GAAG;AACH;;AAEA;AACA;AACA;AACO,SAAS,IAAI,CAAC,OAAO,GAA4B,EAAE,EAA0B;AACpF,EAAE,OAAO,KAAK,CAAC,OAAO,EAAE,sBAAsB,CAAC;AAC/C;;AAEA;AACA;AACA;AACA,SAAS,KAAK;AACd,EAAE,OAAO,GAA4B,EAAE;AACvC,EAAE,0BAA0B;AAC5B,EAA0B;AAC1B,EAAEC,qBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC;;AAEnC,EAAE,MAAM,MAAA,GAASC,aAAY,CAAC;AAC9B,IAAI,GAAG,OAAO;AACd;AACA,IAAI,mBAAmB,EAAE,OAAO,CAAC,uBAAuB,0BAA0B,CAAC,OAAO,CAAC;AAC3F,GAAG,CAAC;;AAEJ;AACA,EAAE,IAAI,MAAA,IAAU,CAAC,OAAO,CAAC,sBAAsB,EAAE;AACjD,IAAIC,0BAAiB,CAAC,MAAM,EAAE;AAC9B,MAAM,cAAc,EAAE,OAAO,CAAC,2BAA2B;AACzD,KAAK,CAAC;AACN,IAAIC,mCAA0B,EAAE;AAChC,EAAE;;AAEF,EAAE,OAAO,MAAM;AACf;;AAEA;AACA;AACA;AACO,SAAS,8BAA8B,CAAC,OAAO,GAA4B,EAAE,EAA0B;AAC9G,EAAE,OAAO,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;AACjC;;;;;;;"}
@@ -1,5 +1,5 @@
1
1
  export { httpIntegration } from './integrations/http.js';
2
- export { nativeNodeFetchIntegration } from './integrations/node-fetch.js';
2
+ export { nativeNodeFetchIntegration } from './integrations/node-fetch/index.js';
3
3
  export { fsIntegration } from './integrations/fs.js';
4
4
  export { expressIntegration, setupExpressErrorHandler } from './integrations/tracing/express.js';
5
5
  export { fastifyIntegration, setupFastifyErrorHandler } from './integrations/tracing/fastify/index.js';
@@ -39,6 +39,6 @@ export { getDefaultIntegrations, getDefaultIntegrationsWithoutPerformance, init,
39
39
  export { initOpenTelemetry, preloadOpenTelemetry } from './sdk/initOtel.js';
40
40
  export { getAutoPerformanceIntegrations } from './integrations/tracing/index.js';
41
41
  export { setOpenTelemetryContextAsyncContextStrategy as setNodeAsyncContextStrategy } from '@sentry/opentelemetry';
42
- export { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, Scope, addBreadcrumb, addEventProcessor, addIntegration, captureCheckIn, captureConsoleIntegration, captureEvent, captureException, captureFeedback, captureMessage, captureSession, close, consoleIntegration, consoleLoggingIntegration, continueTrace, createConsolaReporter, createLangChainCallbackHandler, createTransport, dedupeIntegration, endSession, eventFiltersIntegration, expressErrorHandler, extraErrorDataIntegration, featureFlagsIntegration, flush, functionToStringIntegration, getActiveSpan, getClient, getCurrentScope, getGlobalScope, getIsolationScope, getRootSpan, getSpanDescendants, getSpanStatusFromHttpCode, getTraceData, getTraceMetaTags, httpHeadersToSpanAttributes, inboundFiltersIntegration, instrumentAnthropicAiClient, instrumentGoogleGenAIClient, instrumentLangChainEmbeddings, instrumentLangGraph, instrumentOpenAiClient, instrumentStateGraphCompile, instrumentSupabaseClient, isEnabled, isInitialized, lastEventId, linkedErrorsIntegration, parameterize, profiler, requestDataIntegration, rewriteFramesIntegration, setContext, setConversationId, setCurrentClient, setExtra, setExtras, setHttpStatus, setMeasurement, setTag, setTags, setUser, spanStreamingIntegration, spanToBaggageHeader, spanToJSON, spanToTraceHeader, startInactiveSpan, startNewTrace, startSession, startSpan, startSpanManual, supabaseIntegration, suppressTracing, trpcMiddleware, updateSpanName, winterCGHeadersToDict, withActiveSpan, withIsolationScope, withMonitor, withScope, wrapMcpServerWithSentry, zodErrorsIntegration } from '@sentry/core';
43
- export { NODE_VERSION, NodeClient, SentryContextManager, _INTERNAL_normalizeCollectionInterval, anrIntegration, childProcessIntegration, contextLinesIntegration, createGetModuleFromFilename, createSentryWinstonTransport, cron, defaultStackParser, disableAnrDetectionForCallback, generateInstrumentOnce, getSentryRelease, httpServerIntegration, httpServerSpansIntegration, localVariablesIntegration, logger, makeNodeTransport, metrics, modulesIntegration, nodeContextIntegration, nodeRuntimeMetricsIntegration, onUncaughtExceptionIntegration, onUnhandledRejectionIntegration, pinoIntegration, processSessionIntegration, spotlightIntegration, systemErrorIntegration, validateOpenTelemetrySetup, withStreamedSpan } from '@sentry/node-core';
42
+ export { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, Scope, addBreadcrumb, addEventProcessor, addIntegration, captureCheckIn, captureConsoleIntegration, captureEvent, captureException, captureFeedback, captureMessage, captureSession, close, consoleLoggingIntegration, continueTrace, createConsolaReporter, createLangChainCallbackHandler, createTransport, dedupeIntegration, endSession, eventFiltersIntegration, expressErrorHandler, extraErrorDataIntegration, featureFlagsIntegration, flush, functionToStringIntegration, getActiveSpan, getClient, getCurrentScope, getGlobalScope, getIsolationScope, getRootSpan, getSpanDescendants, getSpanStatusFromHttpCode, getTraceData, getTraceMetaTags, httpHeadersToSpanAttributes, inboundFiltersIntegration, instrumentAnthropicAiClient, instrumentGoogleGenAIClient, instrumentLangChainEmbeddings, instrumentLangGraph, instrumentOpenAiClient, instrumentStateGraphCompile, instrumentSupabaseClient, isEnabled, isInitialized, lastEventId, linkedErrorsIntegration, parameterize, profiler, requestDataIntegration, rewriteFramesIntegration, setContext, setConversationId, setCurrentClient, setExtra, setExtras, setHttpStatus, setMeasurement, setTag, setTags, setUser, spanStreamingIntegration, spanToBaggageHeader, spanToJSON, spanToTraceHeader, startInactiveSpan, startNewTrace, startSession, startSpan, startSpanManual, supabaseIntegration, suppressTracing, trpcMiddleware, updateSpanName, winterCGHeadersToDict, withActiveSpan, withIsolationScope, withMonitor, withScope, wrapMcpServerWithSentry, zodErrorsIntegration } from '@sentry/core';
43
+ export { NODE_VERSION, NodeClient, SentryContextManager, _INTERNAL_normalizeCollectionInterval, anrIntegration, childProcessIntegration, consoleIntegration, contextLinesIntegration, createGetModuleFromFilename, createSentryWinstonTransport, cron, defaultStackParser, disableAnrDetectionForCallback, generateInstrumentOnce, getSentryRelease, httpServerIntegration, httpServerSpansIntegration, localVariablesIntegration, logger, makeNodeTransport, metrics, modulesIntegration, nodeContextIntegration, nodeRuntimeMetricsIntegration, onUncaughtExceptionIntegration, onUnhandledRejectionIntegration, pinoIntegration, processSessionIntegration, spotlightIntegration, systemErrorIntegration, validateOpenTelemetrySetup, withStreamedSpan } from '@sentry/node-core';
44
44
  //# sourceMappingURL=index.js.map
@@ -1,4 +1,4 @@
1
- import { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici';
1
+ import { UndiciInstrumentation } from './vendored/undici.js';
2
2
  import { defineIntegration, stripDataUrlContent, SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME, SEMANTIC_ATTRIBUTE_URL_FULL, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getClient, hasSpansEnabled } from '@sentry/core';
3
3
  import { generateInstrumentOnce, SentryNodeFetchInstrumentation } from '@sentry/node-core';
4
4
 
@@ -102,4 +102,4 @@ function _getConfigWithDefaults(options = {}) {
102
102
  }
103
103
 
104
104
  export { _getConfigWithDefaults, nativeNodeFetchIntegration };
105
- //# sourceMappingURL=node-fetch.js.map
105
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../../src/integrations/node-fetch/index.ts"],"sourcesContent":["import type { UndiciInstrumentationConfig } from './vendored/types';\nimport { UndiciInstrumentation } from './vendored/undici';\nimport type { IntegrationFn } from '@sentry/core';\nimport {\n defineIntegration,\n getClient,\n hasSpansEnabled,\n SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_URL_FULL,\n stripDataUrlContent,\n} from '@sentry/core';\nimport type { NodeClient } from '@sentry/node-core';\nimport { generateInstrumentOnce, SentryNodeFetchInstrumentation } from '@sentry/node-core';\nimport type { NodeClientOptions } from '../../types';\n\nconst INTEGRATION_NAME = 'NodeFetch';\n\ninterface NodeFetchOptions extends Pick<\n UndiciInstrumentationConfig,\n 'requestHook' | 'responseHook' | 'headersToSpanAttributes'\n> {\n /**\n * Whether breadcrumbs should be recorded for requests.\n * Defaults to true\n */\n breadcrumbs?: boolean;\n\n /**\n * If set to false, do not emit any spans.\n * This will ensure that the default UndiciInstrumentation from OpenTelemetry is not setup,\n * only the Sentry-specific instrumentation for breadcrumbs & trace propagation is applied.\n *\n * If `skipOpenTelemetrySetup: true` is configured, this defaults to `false`, otherwise it defaults to `true`.\n */\n spans?: boolean;\n\n /**\n * Whether to inject trace propagation headers (sentry-trace, baggage, traceparent) into outgoing fetch requests.\n *\n * When set to `false`, Sentry will not inject any trace propagation headers, but will still create breadcrumbs\n * (if `breadcrumbs` is enabled). This is useful when `skipOpenTelemetrySetup: true` is configured and you want\n * to avoid duplicate trace headers being injected by both Sentry and OpenTelemetry's UndiciInstrumentation.\n *\n * @default `true`\n */\n tracePropagation?: boolean;\n\n /**\n * Do not capture spans or breadcrumbs for outgoing fetch requests to URLs where the given callback returns `true`.\n * This controls both span & breadcrumb creation - spans will be non recording if tracing is disabled.\n */\n ignoreOutgoingRequests?: (url: string) => boolean;\n}\n\nconst instrumentOtelNodeFetch = generateInstrumentOnce(\n INTEGRATION_NAME,\n UndiciInstrumentation,\n (options: NodeFetchOptions) => {\n return _getConfigWithDefaults(options);\n },\n);\n\nconst instrumentSentryNodeFetch = generateInstrumentOnce(\n `${INTEGRATION_NAME}.sentry`,\n SentryNodeFetchInstrumentation,\n (options: NodeFetchOptions) => {\n return options;\n },\n);\n\nconst _nativeNodeFetchIntegration = ((options: NodeFetchOptions = {}) => {\n return {\n name: 'NodeFetch',\n setupOnce() {\n const instrumentSpans = _shouldInstrumentSpans(options, getClient<NodeClient>()?.getOptions());\n\n // This is the \"regular\" OTEL instrumentation that emits spans\n if (instrumentSpans) {\n instrumentOtelNodeFetch(options);\n }\n\n // This is the Sentry-specific instrumentation that creates breadcrumbs & propagates traces\n // This must be registered after the OTEL one, to ensure that the core trace propagation logic takes presedence\n // Otherwise, the sentry-trace header may be set multiple times\n instrumentSentryNodeFetch(options);\n },\n };\n}) satisfies IntegrationFn;\n\nexport const nativeNodeFetchIntegration = defineIntegration(_nativeNodeFetchIntegration);\n\n// Matching the behavior of the base instrumentation\nfunction getAbsoluteUrl(origin: string, path: string = '/'): string {\n const url = `${origin}`;\n\n if (url.endsWith('/') && path.startsWith('/')) {\n return `${url}${path.slice(1)}`;\n }\n\n if (!url.endsWith('/') && !path.startsWith('/')) {\n return `${url}/${path}`;\n }\n\n return `${url}${path}`;\n}\n\nfunction _shouldInstrumentSpans(options: NodeFetchOptions, clientOptions: Partial<NodeClientOptions> = {}): boolean {\n // If `spans` is passed in, it takes precedence\n // Else, we by default emit spans, unless `skipOpenTelemetrySetup` is set to `true` or spans are not enabled\n return typeof options.spans === 'boolean'\n ? options.spans\n : !clientOptions.skipOpenTelemetrySetup && hasSpansEnabled(clientOptions);\n}\n\n/** Exported only for tests. */\nexport function _getConfigWithDefaults(options: Partial<NodeFetchOptions> = {}): UndiciInstrumentationConfig {\n const instrumentationConfig = {\n requireParentforSpans: false,\n ignoreRequestHook: request => {\n const url = getAbsoluteUrl(request.origin, request.path);\n const _ignoreOutgoingRequests = options.ignoreOutgoingRequests;\n const shouldIgnore = _ignoreOutgoingRequests && url && _ignoreOutgoingRequests(url);\n\n return !!shouldIgnore;\n },\n startSpanHook: request => {\n const url = getAbsoluteUrl(request.origin, request.path);\n\n // Sanitize data URLs to prevent long base64 strings in span attributes\n if (url.startsWith('data:')) {\n const sanitizedUrl = stripDataUrlContent(url);\n return {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.node_fetch',\n 'http.url': sanitizedUrl,\n [SEMANTIC_ATTRIBUTE_URL_FULL]: sanitizedUrl,\n [SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME]: `${request.method || 'GET'} ${sanitizedUrl}`,\n };\n }\n\n return {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.node_fetch',\n };\n },\n requestHook: options.requestHook,\n responseHook: options.responseHook,\n headersToSpanAttributes: options.headersToSpanAttributes,\n } satisfies UndiciInstrumentationConfig;\n\n return instrumentationConfig;\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,482 @@
1
+ import * as diagch from 'diagnostics_channel';
2
+ import { URL } from 'url';
3
+ import { InstrumentationBase, safeExecuteInTheMiddle } from '@opentelemetry/instrumentation';
4
+ import { ValueType, context, trace, INVALID_SPAN_CONTEXT, SpanKind, propagation, SpanStatusCode } from '@opentelemetry/api';
5
+ import { hrTime, hrTimeToMilliseconds, hrTimeDuration } from '@opentelemetry/core';
6
+ import { METRIC_HTTP_CLIENT_REQUEST_DURATION, ATTR_URL_QUERY, ATTR_URL_PATH, ATTR_URL_FULL, ATTR_HTTP_REQUEST_METHOD_ORIGINAL, ATTR_HTTP_RESPONSE_STATUS_CODE, ATTR_ERROR_TYPE, ATTR_HTTP_REQUEST_METHOD, ATTR_SERVER_ADDRESS, ATTR_SERVER_PORT, ATTR_URL_SCHEME, ATTR_USER_AGENT_ORIGINAL, ATTR_NETWORK_PEER_PORT, ATTR_NETWORK_PEER_ADDRESS } from '@opentelemetry/semantic-conventions';
7
+ import { SDK_VERSION } from '@sentry/core';
8
+
9
+ /*
10
+ * Copyright The OpenTelemetry Authors
11
+ *
12
+ * Licensed under the Apache License, Version 2.0 (the "License");
13
+ * you may not use this file except in compliance with the License.
14
+ * You may obtain a copy of the License at
15
+ *
16
+ * https://www.apache.org/licenses/LICENSE-2.0
17
+ *
18
+ * Unless required by applicable law or agreed to in writing, software
19
+ * distributed under the License is distributed on an "AS IS" BASIS,
20
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ * See the License for the specific language governing permissions and
22
+ * limitations under the License.
23
+ *
24
+ * NOTICE from the Sentry authors:
25
+ * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/ed97091c9890dd18e52759f2ea98e9d7593b3ae4/packages/instrumentation-undici
26
+ * - Upstream version: @opentelemetry/instrumentation-undici@0.24.0
27
+ * - Tracking issue: https://github.com/getsentry/sentry-javascript/issues/20165
28
+ * - Minor TypeScript strictness adjustments for this repository's compiler settings
29
+ */
30
+ /* eslint-disable -- vendored @opentelemetry/instrumentation-undici (#20165) */
31
+
32
+
33
+ const PACKAGE_NAME = '@sentry/instrumentation-undici';
34
+
35
+ // A combination of https://github.com/elastic/apm-agent-nodejs and
36
+ // https://github.com/gadget-inc/opentelemetry-instrumentations/blob/main/packages/opentelemetry-instrumentation-undici/src/index.ts
37
+ class UndiciInstrumentation extends InstrumentationBase {
38
+ // Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug and for
39
+ // unsubscribing.
40
+
41
+ __init() {this._recordFromReq = new WeakMap();}
42
+
43
+ constructor(config = {}) {
44
+ super(PACKAGE_NAME, SDK_VERSION, config);UndiciInstrumentation.prototype.__init.call(this); }
45
+
46
+ // No need to instrument files/modules
47
+ init() {
48
+ return undefined;
49
+ }
50
+
51
+ disable() {
52
+ super.disable();
53
+ this._channelSubs.forEach(sub => sub.unsubscribe());
54
+ this._channelSubs.length = 0;
55
+ }
56
+
57
+ enable() {
58
+ // "enabled" handling is currently a bit messy with InstrumentationBase.
59
+ // If constructed with `{enabled: false}`, this `.enable()` is still called,
60
+ // and `this.getConfig().enabled !== this.isEnabled()`, creating confusion.
61
+ //
62
+ // For now, this class will setup for instrumenting if `.enable()` is
63
+ // called, but use `this.getConfig().enabled` to determine if
64
+ // instrumentation should be generated. This covers the more likely common
65
+ // case of config being given a construction time, rather than later via
66
+ // `instance.enable()`, `.disable()`, or `.setConfig()` calls.
67
+ super.enable();
68
+
69
+ // This method is called by the super-class constructor before ours is
70
+ // called. So we need to ensure the property is initalized.
71
+ this._channelSubs = this._channelSubs || [];
72
+
73
+ // Avoid to duplicate subscriptions
74
+ if (this._channelSubs.length > 0) {
75
+ return;
76
+ }
77
+
78
+ this.subscribeToChannel('undici:request:create', this.onRequestCreated.bind(this));
79
+ this.subscribeToChannel('undici:client:sendHeaders', this.onRequestHeaders.bind(this));
80
+ this.subscribeToChannel('undici:request:headers', this.onResponseHeaders.bind(this));
81
+ this.subscribeToChannel('undici:request:trailers', this.onDone.bind(this));
82
+ this.subscribeToChannel('undici:request:error', this.onError.bind(this));
83
+ }
84
+
85
+ _updateMetricInstruments() {
86
+ this._httpClientDurationHistogram = this.meter.createHistogram(METRIC_HTTP_CLIENT_REQUEST_DURATION, {
87
+ description: 'Measures the duration of outbound HTTP requests.',
88
+ unit: 's',
89
+ valueType: ValueType.DOUBLE,
90
+ advice: {
91
+ explicitBucketBoundaries: [0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10],
92
+ },
93
+ });
94
+ }
95
+
96
+ subscribeToChannel(diagnosticChannel, onMessage) {
97
+ // `diagnostics_channel` had a ref counting bug until v18.19.0.
98
+ // https://github.com/nodejs/node/pull/47520
99
+ const [major = 0, minor = 0] = process.version
100
+ .replace('v', '')
101
+ .split('.')
102
+ .map(n => Number(n));
103
+ const useNewSubscribe = major > 18 || (major === 18 && minor >= 19);
104
+
105
+ let unsubscribe;
106
+ if (useNewSubscribe) {
107
+ diagch.subscribe?.(diagnosticChannel, onMessage);
108
+ unsubscribe = () => diagch.unsubscribe?.(diagnosticChannel, onMessage);
109
+ } else {
110
+ const channel = diagch.channel(diagnosticChannel);
111
+ channel.subscribe(onMessage);
112
+ unsubscribe = () => channel.unsubscribe(onMessage);
113
+ }
114
+
115
+ this._channelSubs.push({
116
+ name: diagnosticChannel,
117
+ unsubscribe,
118
+ });
119
+ }
120
+
121
+ parseRequestHeaders(request) {
122
+ const result = new Map();
123
+
124
+ if (Array.isArray(request.headers)) {
125
+ // headers are an array [k1, v2, k2, v2] (undici v6+)
126
+ // values could be string or a string[] for multiple values
127
+ for (let i = 0; i < request.headers.length; i += 2) {
128
+ const key = request.headers[i];
129
+ const value = request.headers[i + 1];
130
+
131
+ // Key should always be a string, but the types don't know that, and let's be safe
132
+ if (typeof key === 'string' && value !== undefined) {
133
+ result.set(key.toLowerCase(), value);
134
+ }
135
+ }
136
+ } else if (typeof request.headers === 'string') {
137
+ // headers are a raw string (undici v5)
138
+ // headers could be repeated in several lines for multiple values
139
+ const headers = request.headers.split('\r\n');
140
+ for (const line of headers) {
141
+ if (!line) {
142
+ continue;
143
+ }
144
+ const colonIndex = line.indexOf(':');
145
+ if (colonIndex === -1) {
146
+ // Invalid header? Probably this can't happen, but again let's be safe.
147
+ continue;
148
+ }
149
+ const key = line.substring(0, colonIndex).toLowerCase();
150
+ const value = line.substring(colonIndex + 1).trim();
151
+ const allValues = result.get(key);
152
+
153
+ if (allValues && Array.isArray(allValues)) {
154
+ allValues.push(value);
155
+ } else if (allValues) {
156
+ result.set(key, [allValues, value]);
157
+ } else {
158
+ result.set(key, value);
159
+ }
160
+ }
161
+ }
162
+ return result;
163
+ }
164
+
165
+ // This is the 1st message we receive for each request (fired after request creation). Here we will
166
+ // create the span and populate some atttributes, then link the span to the request for further
167
+ // span processing
168
+ onRequestCreated({ request }) {
169
+ // Ignore if:
170
+ // - instrumentation is disabled
171
+ // - ignored by config
172
+ // - method is 'CONNECT'
173
+ const config = this.getConfig();
174
+ const enabled = config.enabled !== false;
175
+ const shouldIgnoreReq = safeExecuteInTheMiddle(
176
+ () => !enabled || request.method === 'CONNECT' || config.ignoreRequestHook?.(request),
177
+ e => e && this._diag.error('caught ignoreRequestHook error: ', e),
178
+ true,
179
+ );
180
+
181
+ if (shouldIgnoreReq) {
182
+ return;
183
+ }
184
+
185
+ const startTime = hrTime();
186
+ let requestUrl;
187
+ try {
188
+ requestUrl = new URL(request.path, request.origin);
189
+ } catch (err) {
190
+ this._diag.warn('could not determine url.full:', err);
191
+ // Skip instrumenting this request.
192
+ return;
193
+ }
194
+ const urlScheme = requestUrl.protocol.replace(':', '');
195
+ const requestMethod = this.getRequestMethod(request.method);
196
+ const attributes = {
197
+ [ATTR_HTTP_REQUEST_METHOD]: requestMethod,
198
+ [ATTR_HTTP_REQUEST_METHOD_ORIGINAL]: request.method,
199
+ [ATTR_URL_FULL]: requestUrl.toString(),
200
+ [ATTR_URL_PATH]: requestUrl.pathname,
201
+ [ATTR_URL_QUERY]: requestUrl.search,
202
+ [ATTR_URL_SCHEME]: urlScheme,
203
+ };
204
+
205
+ const schemePorts = { https: '443', http: '80' };
206
+ const serverAddress = requestUrl.hostname;
207
+ const serverPort = requestUrl.port || schemePorts[urlScheme];
208
+
209
+ attributes[ATTR_SERVER_ADDRESS] = serverAddress;
210
+ if (serverPort && !isNaN(Number(serverPort))) {
211
+ attributes[ATTR_SERVER_PORT] = Number(serverPort);
212
+ }
213
+
214
+ // Get user agent from headers
215
+ const headersMap = this.parseRequestHeaders(request);
216
+ const userAgentValues = headersMap.get('user-agent');
217
+
218
+ if (userAgentValues) {
219
+ // NOTE: having multiple user agents is not expected so
220
+ // we're going to take last one like `curl` does
221
+ // ref: https://curl.se/docs/manpage.html#-A
222
+ const userAgent = Array.isArray(userAgentValues) ? userAgentValues[userAgentValues.length - 1] : userAgentValues;
223
+ attributes[ATTR_USER_AGENT_ORIGINAL] = userAgent;
224
+ }
225
+
226
+ // Get attributes from the hook if present
227
+ const hookAttributes = safeExecuteInTheMiddle(
228
+ () => config.startSpanHook?.(request),
229
+ e => e && this._diag.error('caught startSpanHook error: ', e),
230
+ true,
231
+ );
232
+ if (hookAttributes) {
233
+ Object.entries(hookAttributes).forEach(([key, val]) => {
234
+ attributes[key] = val;
235
+ });
236
+ }
237
+
238
+ // Check if parent span is required via config and:
239
+ // - if a parent is required but not present, we use a `NoopSpan` to still
240
+ // propagate context without recording it.
241
+ // - create a span otherwise
242
+ const activeCtx = context.active();
243
+ const currentSpan = trace.getSpan(activeCtx);
244
+ let span;
245
+
246
+ if (config.requireParentforSpans && (!currentSpan || !trace.isSpanContextValid(currentSpan.spanContext()))) {
247
+ span = trace.wrapSpanContext(INVALID_SPAN_CONTEXT);
248
+ } else {
249
+ span = this.tracer.startSpan(
250
+ requestMethod === '_OTHER' ? 'HTTP' : requestMethod,
251
+ {
252
+ kind: SpanKind.CLIENT,
253
+ attributes: attributes,
254
+ },
255
+ activeCtx,
256
+ );
257
+ }
258
+
259
+ // Execute the request hook if defined
260
+ safeExecuteInTheMiddle(
261
+ () => config.requestHook?.(span, request),
262
+ e => e && this._diag.error('caught requestHook error: ', e),
263
+ true,
264
+ );
265
+
266
+ // Context propagation goes last so no hook can tamper
267
+ // the propagation headers
268
+ const requestContext = trace.setSpan(context.active(), span);
269
+ const addedHeaders = {};
270
+ propagation.inject(requestContext, addedHeaders);
271
+
272
+ const headerEntries = Object.entries(addedHeaders);
273
+
274
+ for (let i = 0; i < headerEntries.length; i++) {
275
+ const pair = headerEntries[i];
276
+ if (!pair) {
277
+ continue;
278
+ }
279
+ const [k, v] = pair;
280
+
281
+ if (typeof request.addHeader === 'function') {
282
+ request.addHeader(k, v);
283
+ } else if (typeof request.headers === 'string') {
284
+ request.headers += `${k}: ${v}\r\n`;
285
+ } else if (Array.isArray(request.headers)) {
286
+ // undici@6.11.0 accidentally, briefly removed `request.addHeader()`.
287
+ request.headers.push(k, v);
288
+ }
289
+ }
290
+ this._recordFromReq.set(request, { span, attributes, startTime });
291
+ }
292
+
293
+ // This is the 2nd message we receive for each request. It is fired when connection with
294
+ // the remote is established and about to send the first byte. Here we do have info about the
295
+ // remote address and port so we can populate some `network.*` attributes into the span
296
+ onRequestHeaders({ request, socket }) {
297
+ const record = this._recordFromReq.get(request);
298
+
299
+ if (!record) {
300
+ return;
301
+ }
302
+
303
+ const config = this.getConfig();
304
+ const { span } = record;
305
+ const { remoteAddress, remotePort } = socket;
306
+ const spanAttributes = {
307
+ [ATTR_NETWORK_PEER_ADDRESS]: remoteAddress,
308
+ [ATTR_NETWORK_PEER_PORT]: remotePort,
309
+ };
310
+
311
+ // After hooks have been processed (which may modify request headers)
312
+ // we can collect the headers based on the configuration
313
+ if (config.headersToSpanAttributes?.requestHeaders) {
314
+ const headersToAttribs = new Set(config.headersToSpanAttributes.requestHeaders.map(n => n.toLowerCase()));
315
+ const headersMap = this.parseRequestHeaders(request);
316
+
317
+ for (const [name, value] of headersMap.entries()) {
318
+ if (headersToAttribs.has(name)) {
319
+ const attrValue = Array.isArray(value) ? value : [value];
320
+ spanAttributes[`http.request.header.${name}`] = attrValue;
321
+ }
322
+ }
323
+ }
324
+
325
+ span.setAttributes(spanAttributes);
326
+ }
327
+
328
+ // This is the 3rd message we get for each request and it's fired when the server
329
+ // headers are received, body may not be accessible yet.
330
+ // From the response headers we can set the status and content length
331
+ onResponseHeaders({ request, response }) {
332
+ const record = this._recordFromReq.get(request);
333
+
334
+ if (!record) {
335
+ return;
336
+ }
337
+
338
+ const { span, attributes } = record;
339
+ const spanAttributes = {
340
+ [ATTR_HTTP_RESPONSE_STATUS_CODE]: response.statusCode,
341
+ };
342
+
343
+ const config = this.getConfig();
344
+
345
+ // Execute the response hook if defined
346
+ safeExecuteInTheMiddle(
347
+ () => config.responseHook?.(span, { request, response }),
348
+ e => e && this._diag.error('caught responseHook error: ', e),
349
+ true,
350
+ );
351
+
352
+ if (config.headersToSpanAttributes?.responseHeaders) {
353
+ const headersToAttribs = new Set();
354
+ config.headersToSpanAttributes?.responseHeaders.forEach(name => headersToAttribs.add(name.toLowerCase()));
355
+
356
+ for (let idx = 0; idx < response.headers.length; idx = idx + 2) {
357
+ const nameBuf = response.headers[idx];
358
+ const valueBuf = response.headers[idx + 1];
359
+ if (nameBuf === undefined || valueBuf === undefined) {
360
+ continue;
361
+ }
362
+ const name = nameBuf.toString().toLowerCase();
363
+ const value = valueBuf;
364
+
365
+ if (headersToAttribs.has(name)) {
366
+ const attrName = `http.response.header.${name}`;
367
+ if (!Object.prototype.hasOwnProperty.call(spanAttributes, attrName)) {
368
+ spanAttributes[attrName] = [value.toString()];
369
+ } else {
370
+ (spanAttributes[attrName] ).push(value.toString());
371
+ }
372
+ }
373
+ }
374
+ }
375
+
376
+ span.setAttributes(spanAttributes);
377
+ span.setStatus({
378
+ code: response.statusCode >= 400 ? SpanStatusCode.ERROR : SpanStatusCode.UNSET,
379
+ });
380
+ record.attributes = Object.assign(attributes, spanAttributes);
381
+ }
382
+
383
+ // This is the last event we receive if the request went without any errors
384
+ onDone({ request }) {
385
+ const record = this._recordFromReq.get(request);
386
+
387
+ if (!record) {
388
+ return;
389
+ }
390
+
391
+ const { span, attributes, startTime } = record;
392
+
393
+ // End the span
394
+ span.end();
395
+ this._recordFromReq.delete(request);
396
+
397
+ // Record metrics
398
+ this.recordRequestDuration(attributes, startTime);
399
+ }
400
+
401
+ // This is the event we get when something is wrong in the request like
402
+ // - invalid options when calling `fetch` global API or any undici method for request
403
+ // - connectivity errors such as unreachable host
404
+ // - requests aborted through an `AbortController.signal`
405
+ // NOTE: server errors are considered valid responses and it's the lib consumer
406
+ // who should deal with that.
407
+ onError({ request, error }) {
408
+ const record = this._recordFromReq.get(request);
409
+
410
+ if (!record) {
411
+ return;
412
+ }
413
+
414
+ const { span, attributes, startTime } = record;
415
+
416
+ // NOTE: in `undici@6.3.0` when request aborted the error type changes from
417
+ // a custom error (`RequestAbortedError`) to a built-in `DOMException` carrying
418
+ // some differences:
419
+ // - `code` is from DOMEXception (ABORT_ERR: 20)
420
+ // - `message` changes
421
+ // - stacktrace is smaller and contains node internal frames
422
+ span.recordException(error);
423
+ span.setStatus({
424
+ code: SpanStatusCode.ERROR,
425
+ message: error.message,
426
+ });
427
+ span.end();
428
+ this._recordFromReq.delete(request);
429
+
430
+ // Record metrics (with the error)
431
+ attributes[ATTR_ERROR_TYPE] = error.message;
432
+ this.recordRequestDuration(attributes, startTime);
433
+ }
434
+
435
+ recordRequestDuration(attributes, startTime) {
436
+ // Time to record metrics
437
+ const metricsAttributes = {};
438
+ // Get the attribs already in span attributes
439
+ const keysToCopy = [
440
+ ATTR_HTTP_RESPONSE_STATUS_CODE,
441
+ ATTR_HTTP_REQUEST_METHOD,
442
+ ATTR_SERVER_ADDRESS,
443
+ ATTR_SERVER_PORT,
444
+ ATTR_URL_SCHEME,
445
+ ATTR_ERROR_TYPE,
446
+ ];
447
+ keysToCopy.forEach(key => {
448
+ if (key in attributes) {
449
+ metricsAttributes[key] = attributes[key];
450
+ }
451
+ });
452
+
453
+ // Take the duration and record it
454
+ const durationSeconds = hrTimeToMilliseconds(hrTimeDuration(startTime, hrTime())) / 1000;
455
+ this._httpClientDurationHistogram.record(durationSeconds, metricsAttributes);
456
+ }
457
+
458
+ getRequestMethod(original) {
459
+ const knownMethods = {
460
+ CONNECT: true,
461
+ OPTIONS: true,
462
+ HEAD: true,
463
+ GET: true,
464
+ POST: true,
465
+ PUT: true,
466
+ PATCH: true,
467
+ DELETE: true,
468
+ TRACE: true,
469
+ // QUERY from https://datatracker.ietf.org/doc/draft-ietf-httpbis-safe-method-w-body/
470
+ QUERY: true,
471
+ };
472
+
473
+ if (original.toUpperCase() in knownMethods) {
474
+ return original.toUpperCase();
475
+ }
476
+
477
+ return '_OTHER';
478
+ }
479
+ }
480
+
481
+ export { UndiciInstrumentation };
482
+ //# sourceMappingURL=undici.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"undici.js","sources":["../../../../../src/integrations/node-fetch/vendored/undici.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 * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/ed97091c9890dd18e52759f2ea98e9d7593b3ae4/packages/instrumentation-undici\n * - Upstream version: @opentelemetry/instrumentation-undici@0.24.0\n * - Tracking issue: https://github.com/getsentry/sentry-javascript/issues/20165\n * - Minor TypeScript strictness adjustments for this repository's compiler settings\n */\n/* eslint-disable -- vendored @opentelemetry/instrumentation-undici (#20165) */\n\nimport * as diagch from 'diagnostics_channel';\nimport { URL } from 'url';\n\nimport { InstrumentationBase, safeExecuteInTheMiddle } from '@opentelemetry/instrumentation';\nimport type { Attributes, Histogram, HrTime, Span } from '@opentelemetry/api';\nimport {\n context,\n INVALID_SPAN_CONTEXT,\n propagation,\n SpanKind,\n SpanStatusCode,\n trace,\n ValueType,\n} from '@opentelemetry/api';\nimport { hrTime, hrTimeDuration, hrTimeToMilliseconds } from '@opentelemetry/core';\nimport {\n ATTR_ERROR_TYPE,\n ATTR_HTTP_REQUEST_METHOD,\n ATTR_HTTP_REQUEST_METHOD_ORIGINAL,\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_NETWORK_PEER_ADDRESS,\n ATTR_NETWORK_PEER_PORT,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n ATTR_URL_FULL,\n ATTR_URL_PATH,\n ATTR_URL_QUERY,\n ATTR_URL_SCHEME,\n ATTR_USER_AGENT_ORIGINAL,\n METRIC_HTTP_CLIENT_REQUEST_DURATION,\n} from '@opentelemetry/semantic-conventions';\n\nimport type {\n ListenerRecord,\n RequestHeadersMessage,\n RequestMessage,\n RequestTrailersMessage,\n ResponseHeadersMessage,\n} from './internal-types';\nimport type { UndiciInstrumentationConfig, UndiciRequest } from './types';\n\nimport { SDK_VERSION } from '@sentry/core';\n\ninterface InstrumentationRecord {\n span: Span;\n attributes: Attributes;\n startTime: HrTime;\n}\n\nconst PACKAGE_NAME = '@sentry/instrumentation-undici';\n\n// A combination of https://github.com/elastic/apm-agent-nodejs and\n// https://github.com/gadget-inc/opentelemetry-instrumentations/blob/main/packages/opentelemetry-instrumentation-undici/src/index.ts\nexport class UndiciInstrumentation extends InstrumentationBase<UndiciInstrumentationConfig> {\n // Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug and for\n // unsubscribing.\n declare private _channelSubs: Array<ListenerRecord>;\n private _recordFromReq = new WeakMap<UndiciRequest, InstrumentationRecord>();\n\n declare private _httpClientDurationHistogram: Histogram;\n\n constructor(config: UndiciInstrumentationConfig = {}) {\n super(PACKAGE_NAME, SDK_VERSION, config);\n }\n\n // No need to instrument files/modules\n protected override init() {\n return undefined;\n }\n\n override disable(): void {\n super.disable();\n this._channelSubs.forEach(sub => sub.unsubscribe());\n this._channelSubs.length = 0;\n }\n\n override enable(): void {\n // \"enabled\" handling is currently a bit messy with InstrumentationBase.\n // If constructed with `{enabled: false}`, this `.enable()` is still called,\n // and `this.getConfig().enabled !== this.isEnabled()`, creating confusion.\n //\n // For now, this class will setup for instrumenting if `.enable()` is\n // called, but use `this.getConfig().enabled` to determine if\n // instrumentation should be generated. This covers the more likely common\n // case of config being given a construction time, rather than later via\n // `instance.enable()`, `.disable()`, or `.setConfig()` calls.\n super.enable();\n\n // This method is called by the super-class constructor before ours is\n // called. So we need to ensure the property is initalized.\n this._channelSubs = this._channelSubs || [];\n\n // Avoid to duplicate subscriptions\n if (this._channelSubs.length > 0) {\n return;\n }\n\n this.subscribeToChannel('undici:request:create', this.onRequestCreated.bind(this));\n this.subscribeToChannel('undici:client:sendHeaders', this.onRequestHeaders.bind(this));\n this.subscribeToChannel('undici:request:headers', this.onResponseHeaders.bind(this));\n this.subscribeToChannel('undici:request:trailers', this.onDone.bind(this));\n this.subscribeToChannel('undici:request:error', this.onError.bind(this));\n }\n\n protected override _updateMetricInstruments() {\n this._httpClientDurationHistogram = this.meter.createHistogram(METRIC_HTTP_CLIENT_REQUEST_DURATION, {\n description: 'Measures the duration of outbound HTTP requests.',\n unit: 's',\n valueType: ValueType.DOUBLE,\n advice: {\n explicitBucketBoundaries: [0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10],\n },\n });\n }\n\n private subscribeToChannel(diagnosticChannel: string, onMessage: (message: any, name: string | symbol) => void) {\n // `diagnostics_channel` had a ref counting bug until v18.19.0.\n // https://github.com/nodejs/node/pull/47520\n const [major = 0, minor = 0] = process.version\n .replace('v', '')\n .split('.')\n .map(n => Number(n));\n const useNewSubscribe = major > 18 || (major === 18 && minor >= 19);\n\n let unsubscribe: () => void;\n if (useNewSubscribe) {\n diagch.subscribe?.(diagnosticChannel, onMessage);\n unsubscribe = () => diagch.unsubscribe?.(diagnosticChannel, onMessage);\n } else {\n const channel = diagch.channel(diagnosticChannel);\n channel.subscribe(onMessage);\n unsubscribe = () => channel.unsubscribe(onMessage);\n }\n\n this._channelSubs.push({\n name: diagnosticChannel,\n unsubscribe,\n });\n }\n\n private parseRequestHeaders(request: UndiciRequest) {\n const result = new Map<string, string | string[]>();\n\n if (Array.isArray(request.headers)) {\n // headers are an array [k1, v2, k2, v2] (undici v6+)\n // values could be string or a string[] for multiple values\n for (let i = 0; i < request.headers.length; i += 2) {\n const key = request.headers[i];\n const value = request.headers[i + 1];\n\n // Key should always be a string, but the types don't know that, and let's be safe\n if (typeof key === 'string' && value !== undefined) {\n result.set(key.toLowerCase(), value);\n }\n }\n } else if (typeof request.headers === 'string') {\n // headers are a raw string (undici v5)\n // headers could be repeated in several lines for multiple values\n const headers = request.headers.split('\\r\\n');\n for (const line of headers) {\n if (!line) {\n continue;\n }\n const colonIndex = line.indexOf(':');\n if (colonIndex === -1) {\n // Invalid header? Probably this can't happen, but again let's be safe.\n continue;\n }\n const key = line.substring(0, colonIndex).toLowerCase();\n const value = line.substring(colonIndex + 1).trim();\n const allValues = result.get(key);\n\n if (allValues && Array.isArray(allValues)) {\n allValues.push(value);\n } else if (allValues) {\n result.set(key, [allValues, value]);\n } else {\n result.set(key, value);\n }\n }\n }\n return result;\n }\n\n // This is the 1st message we receive for each request (fired after request creation). Here we will\n // create the span and populate some atttributes, then link the span to the request for further\n // span processing\n private onRequestCreated({ request }: RequestMessage): void {\n // Ignore if:\n // - instrumentation is disabled\n // - ignored by config\n // - method is 'CONNECT'\n const config = this.getConfig();\n const enabled = config.enabled !== false;\n const shouldIgnoreReq = safeExecuteInTheMiddle(\n () => !enabled || request.method === 'CONNECT' || config.ignoreRequestHook?.(request),\n e => e && this._diag.error('caught ignoreRequestHook error: ', e),\n true,\n );\n\n if (shouldIgnoreReq) {\n return;\n }\n\n const startTime = hrTime();\n let requestUrl;\n try {\n requestUrl = new URL(request.path, request.origin);\n } catch (err) {\n this._diag.warn('could not determine url.full:', err);\n // Skip instrumenting this request.\n return;\n }\n const urlScheme = requestUrl.protocol.replace(':', '');\n const requestMethod = this.getRequestMethod(request.method);\n const attributes: Attributes = {\n [ATTR_HTTP_REQUEST_METHOD]: requestMethod,\n [ATTR_HTTP_REQUEST_METHOD_ORIGINAL]: request.method,\n [ATTR_URL_FULL]: requestUrl.toString(),\n [ATTR_URL_PATH]: requestUrl.pathname,\n [ATTR_URL_QUERY]: requestUrl.search,\n [ATTR_URL_SCHEME]: urlScheme,\n };\n\n const schemePorts: Record<string, string> = { https: '443', http: '80' };\n const serverAddress = requestUrl.hostname;\n const serverPort = requestUrl.port || schemePorts[urlScheme];\n\n attributes[ATTR_SERVER_ADDRESS] = serverAddress;\n if (serverPort && !isNaN(Number(serverPort))) {\n attributes[ATTR_SERVER_PORT] = Number(serverPort);\n }\n\n // Get user agent from headers\n const headersMap = this.parseRequestHeaders(request);\n const userAgentValues = headersMap.get('user-agent');\n\n if (userAgentValues) {\n // NOTE: having multiple user agents is not expected so\n // we're going to take last one like `curl` does\n // ref: https://curl.se/docs/manpage.html#-A\n const userAgent = Array.isArray(userAgentValues) ? userAgentValues[userAgentValues.length - 1] : userAgentValues;\n attributes[ATTR_USER_AGENT_ORIGINAL] = userAgent;\n }\n\n // Get attributes from the hook if present\n const hookAttributes = safeExecuteInTheMiddle(\n () => config.startSpanHook?.(request),\n e => e && this._diag.error('caught startSpanHook error: ', e),\n true,\n );\n if (hookAttributes) {\n Object.entries(hookAttributes).forEach(([key, val]) => {\n attributes[key] = val;\n });\n }\n\n // Check if parent span is required via config and:\n // - if a parent is required but not present, we use a `NoopSpan` to still\n // propagate context without recording it.\n // - create a span otherwise\n const activeCtx = context.active();\n const currentSpan = trace.getSpan(activeCtx);\n let span: Span;\n\n if (config.requireParentforSpans && (!currentSpan || !trace.isSpanContextValid(currentSpan.spanContext()))) {\n span = trace.wrapSpanContext(INVALID_SPAN_CONTEXT);\n } else {\n span = this.tracer.startSpan(\n requestMethod === '_OTHER' ? 'HTTP' : requestMethod,\n {\n kind: SpanKind.CLIENT,\n attributes: attributes,\n },\n activeCtx,\n );\n }\n\n // Execute the request hook if defined\n safeExecuteInTheMiddle(\n () => config.requestHook?.(span, request),\n e => e && this._diag.error('caught requestHook error: ', e),\n true,\n );\n\n // Context propagation goes last so no hook can tamper\n // the propagation headers\n const requestContext = trace.setSpan(context.active(), span);\n const addedHeaders: Record<string, string> = {};\n propagation.inject(requestContext, addedHeaders);\n\n const headerEntries = Object.entries(addedHeaders);\n\n for (let i = 0; i < headerEntries.length; i++) {\n const pair = headerEntries[i];\n if (!pair) {\n continue;\n }\n const [k, v] = pair;\n\n if (typeof request.addHeader === 'function') {\n request.addHeader(k, v);\n } else if (typeof request.headers === 'string') {\n request.headers += `${k}: ${v}\\r\\n`;\n } else if (Array.isArray(request.headers)) {\n // undici@6.11.0 accidentally, briefly removed `request.addHeader()`.\n request.headers.push(k, v);\n }\n }\n this._recordFromReq.set(request, { span, attributes, startTime });\n }\n\n // This is the 2nd message we receive for each request. It is fired when connection with\n // the remote is established and about to send the first byte. Here we do have info about the\n // remote address and port so we can populate some `network.*` attributes into the span\n private onRequestHeaders({ request, socket }: RequestHeadersMessage): void {\n const record = this._recordFromReq.get(request);\n\n if (!record) {\n return;\n }\n\n const config = this.getConfig();\n const { span } = record;\n const { remoteAddress, remotePort } = socket;\n const spanAttributes: Attributes = {\n [ATTR_NETWORK_PEER_ADDRESS]: remoteAddress,\n [ATTR_NETWORK_PEER_PORT]: remotePort,\n };\n\n // After hooks have been processed (which may modify request headers)\n // we can collect the headers based on the configuration\n if (config.headersToSpanAttributes?.requestHeaders) {\n const headersToAttribs = new Set(config.headersToSpanAttributes.requestHeaders.map(n => n.toLowerCase()));\n const headersMap = this.parseRequestHeaders(request);\n\n for (const [name, value] of headersMap.entries()) {\n if (headersToAttribs.has(name)) {\n const attrValue = Array.isArray(value) ? value : [value];\n spanAttributes[`http.request.header.${name}`] = attrValue;\n }\n }\n }\n\n span.setAttributes(spanAttributes);\n }\n\n // This is the 3rd message we get for each request and it's fired when the server\n // headers are received, body may not be accessible yet.\n // From the response headers we can set the status and content length\n private onResponseHeaders({ request, response }: ResponseHeadersMessage): void {\n const record = this._recordFromReq.get(request);\n\n if (!record) {\n return;\n }\n\n const { span, attributes } = record;\n const spanAttributes: Attributes = {\n [ATTR_HTTP_RESPONSE_STATUS_CODE]: response.statusCode,\n };\n\n const config = this.getConfig();\n\n // Execute the response hook if defined\n safeExecuteInTheMiddle(\n () => config.responseHook?.(span, { request, response }),\n e => e && this._diag.error('caught responseHook error: ', e),\n true,\n );\n\n if (config.headersToSpanAttributes?.responseHeaders) {\n const headersToAttribs = new Set();\n config.headersToSpanAttributes?.responseHeaders.forEach(name => headersToAttribs.add(name.toLowerCase()));\n\n for (let idx = 0; idx < response.headers.length; idx = idx + 2) {\n const nameBuf = response.headers[idx];\n const valueBuf = response.headers[idx + 1];\n if (nameBuf === undefined || valueBuf === undefined) {\n continue;\n }\n const name = nameBuf.toString().toLowerCase();\n const value = valueBuf;\n\n if (headersToAttribs.has(name)) {\n const attrName = `http.response.header.${name}`;\n if (!Object.prototype.hasOwnProperty.call(spanAttributes, attrName)) {\n spanAttributes[attrName] = [value.toString()];\n } else {\n (spanAttributes[attrName] as string[]).push(value.toString());\n }\n }\n }\n }\n\n span.setAttributes(spanAttributes);\n span.setStatus({\n code: response.statusCode >= 400 ? SpanStatusCode.ERROR : SpanStatusCode.UNSET,\n });\n record.attributes = Object.assign(attributes, spanAttributes);\n }\n\n // This is the last event we receive if the request went without any errors\n private onDone({ request }: RequestTrailersMessage): void {\n const record = this._recordFromReq.get(request);\n\n if (!record) {\n return;\n }\n\n const { span, attributes, startTime } = record;\n\n // End the span\n span.end();\n this._recordFromReq.delete(request);\n\n // Record metrics\n this.recordRequestDuration(attributes, startTime);\n }\n\n // This is the event we get when something is wrong in the request like\n // - invalid options when calling `fetch` global API or any undici method for request\n // - connectivity errors such as unreachable host\n // - requests aborted through an `AbortController.signal`\n // NOTE: server errors are considered valid responses and it's the lib consumer\n // who should deal with that.\n private onError({ request, error }: any): void {\n const record = this._recordFromReq.get(request);\n\n if (!record) {\n return;\n }\n\n const { span, attributes, startTime } = record;\n\n // NOTE: in `undici@6.3.0` when request aborted the error type changes from\n // a custom error (`RequestAbortedError`) to a built-in `DOMException` carrying\n // some differences:\n // - `code` is from DOMEXception (ABORT_ERR: 20)\n // - `message` changes\n // - stacktrace is smaller and contains node internal frames\n span.recordException(error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n span.end();\n this._recordFromReq.delete(request);\n\n // Record metrics (with the error)\n attributes[ATTR_ERROR_TYPE] = error.message;\n this.recordRequestDuration(attributes, startTime);\n }\n\n private recordRequestDuration(attributes: Attributes, startTime: HrTime) {\n // Time to record metrics\n const metricsAttributes: Attributes = {};\n // Get the attribs already in span attributes\n const keysToCopy = [\n ATTR_HTTP_RESPONSE_STATUS_CODE,\n ATTR_HTTP_REQUEST_METHOD,\n ATTR_SERVER_ADDRESS,\n ATTR_SERVER_PORT,\n ATTR_URL_SCHEME,\n ATTR_ERROR_TYPE,\n ];\n keysToCopy.forEach(key => {\n if (key in attributes) {\n metricsAttributes[key] = attributes[key];\n }\n });\n\n // Take the duration and record it\n const durationSeconds = hrTimeToMilliseconds(hrTimeDuration(startTime, hrTime())) / 1000;\n this._httpClientDurationHistogram.record(durationSeconds, metricsAttributes);\n }\n\n private getRequestMethod(original: string): string {\n const knownMethods = {\n CONNECT: true,\n OPTIONS: true,\n HEAD: true,\n GET: true,\n POST: true,\n PUT: true,\n PATCH: true,\n DELETE: true,\n TRACE: true,\n // QUERY from https://datatracker.ietf.org/doc/draft-ietf-httpbis-safe-method-w-body/\n QUERY: true,\n };\n\n if (original.toUpperCase() in knownMethods) {\n return original.toUpperCase();\n }\n\n return '_OTHER';\n }\n}\n"],"names":[],"mappings":"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"}