@sentry/node 11.0.0-alpha.0 → 11.0.0-alpha.2
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.
- package/build/cjs/bundler-plugin/esbuild.js.map +1 -1
- package/build/cjs/bundler-plugin/rollup.js.map +1 -1
- package/build/cjs/bundler-plugin/vite.js.map +1 -1
- package/build/cjs/bundler-plugin/webpack.js.map +1 -1
- package/build/cjs/index.js +53 -53
- package/build/cjs/integrations/anr/index.js +1 -1
- package/build/cjs/integrations/childProcess.js +0 -24
- package/build/cjs/integrations/childProcess.js.map +1 -1
- package/build/cjs/integrations/fs/vendored/instrumentation.js +2 -1
- package/build/cjs/integrations/fs/vendored/instrumentation.js.map +1 -1
- package/build/cjs/integrations/http/SentryHttpInstrumentation.js +2 -8
- package/build/cjs/integrations/http/SentryHttpInstrumentation.js.map +1 -1
- package/build/cjs/integrations/http/httpServerIntegration.js.map +1 -1
- package/build/cjs/integrations/http/httpServerSpansIntegration.js +34 -62
- package/build/cjs/integrations/http/httpServerSpansIntegration.js.map +1 -1
- package/build/cjs/integrations/http/index.js +9 -27
- package/build/cjs/integrations/http/index.js.map +1 -1
- package/build/cjs/integrations/local-variables/local-variables-async.js +1 -1
- package/build/cjs/integrations/node-fetch/undici-instrumentation.js +3 -5
- package/build/cjs/integrations/node-fetch/undici-instrumentation.js.map +1 -1
- package/build/cjs/integrations/pino.js +2 -3
- package/build/cjs/integrations/pino.js.map +1 -1
- package/build/cjs/integrations/processSession.js +1 -1
- package/build/cjs/integrations/processSession.js.map +1 -1
- package/build/cjs/integrations/tracing/hapi.js +10 -0
- package/build/cjs/integrations/tracing/hapi.js.map +1 -0
- package/build/cjs/integrations/tracing/index.js +1 -34
- package/build/cjs/integrations/tracing/index.js.map +1 -1
- package/build/cjs/integrations/tracing/koa.js +10 -0
- package/build/cjs/integrations/tracing/koa.js.map +1 -0
- package/build/cjs/integrations/workerThreads.js +35 -0
- package/build/cjs/integrations/workerThreads.js.map +1 -0
- package/build/cjs/sdk/client.js +23 -13
- package/build/cjs/sdk/client.js.map +1 -1
- package/build/cjs/sdk/index.js +19 -34
- package/build/cjs/sdk/index.js.map +1 -1
- package/build/cjs/sdk/initOtel.js +1 -10
- package/build/cjs/sdk/initOtel.js.map +1 -1
- package/build/cjs/transports/http.js +10 -3
- package/build/cjs/transports/http.js.map +1 -1
- package/build/cjs/utils/outgoingFetchRequest.js +1 -1
- package/build/cjs/utils/outgoingFetchRequest.js.map +1 -1
- package/build/esm/bundler-plugin/esbuild.js.map +1 -1
- package/build/esm/bundler-plugin/rollup.js.map +1 -1
- package/build/esm/bundler-plugin/vite.js.map +1 -1
- package/build/esm/bundler-plugin/webpack.js.map +1 -1
- package/build/esm/index.js +6 -8
- package/build/esm/index.js.map +1 -1
- package/build/esm/integrations/anr/index.js +1 -1
- package/build/esm/integrations/anr/worker-script.js +2 -2
- package/build/esm/integrations/childProcess.js +1 -25
- package/build/esm/integrations/childProcess.js.map +1 -1
- package/build/esm/integrations/fs/vendored/instrumentation.js +2 -1
- package/build/esm/integrations/fs/vendored/instrumentation.js.map +1 -1
- package/build/esm/integrations/http/SentryHttpInstrumentation.js +3 -9
- package/build/esm/integrations/http/SentryHttpInstrumentation.js.map +1 -1
- package/build/esm/integrations/http/httpServerIntegration.js.map +1 -1
- package/build/esm/integrations/http/httpServerSpansIntegration.js +36 -64
- package/build/esm/integrations/http/httpServerSpansIntegration.js.map +1 -1
- package/build/esm/integrations/http/index.js +10 -28
- package/build/esm/integrations/http/index.js.map +1 -1
- package/build/esm/integrations/local-variables/local-variables-async.js +1 -1
- package/build/esm/integrations/local-variables/worker-script.js +1 -1
- package/build/esm/integrations/node-fetch/undici-instrumentation.js +5 -7
- package/build/esm/integrations/node-fetch/undici-instrumentation.js.map +1 -1
- package/build/esm/integrations/pino.js +2 -3
- package/build/esm/integrations/pino.js.map +1 -1
- package/build/esm/integrations/processSession.js +1 -1
- package/build/esm/integrations/processSession.js.map +1 -1
- package/build/esm/integrations/tracing/hapi.js +8 -0
- package/build/esm/integrations/tracing/hapi.js.map +1 -0
- package/build/esm/integrations/tracing/index.js +2 -35
- package/build/esm/integrations/tracing/index.js.map +1 -1
- package/build/esm/integrations/tracing/koa.js +8 -0
- package/build/esm/integrations/tracing/koa.js.map +1 -0
- package/build/esm/integrations/workerThreads.js +33 -0
- package/build/esm/integrations/workerThreads.js.map +1 -0
- package/build/esm/package.json +1 -1
- package/build/esm/sdk/client.js +23 -13
- package/build/esm/sdk/client.js.map +1 -1
- package/build/esm/sdk/index.js +14 -29
- package/build/esm/sdk/index.js.map +1 -1
- package/build/esm/sdk/initOtel.js +4 -12
- package/build/esm/sdk/initOtel.js.map +1 -1
- package/build/esm/transports/http.js +10 -3
- package/build/esm/transports/http.js.map +1 -1
- package/build/esm/utils/outgoingFetchRequest.js +2 -2
- package/build/esm/utils/outgoingFetchRequest.js.map +1 -1
- package/build/types/bundler-plugin/esbuild.d.ts +3 -4
- package/build/types/bundler-plugin/esbuild.d.ts.map +1 -1
- package/build/types/bundler-plugin/rollup.d.ts +3 -4
- package/build/types/bundler-plugin/rollup.d.ts.map +1 -1
- package/build/types/bundler-plugin/vite.d.ts +3 -4
- package/build/types/bundler-plugin/vite.d.ts.map +1 -1
- package/build/types/bundler-plugin/webpack.d.ts +2 -2
- package/build/types/bundler-plugin/webpack.d.ts.map +1 -1
- package/build/types/index.d.ts +7 -7
- package/build/types/index.d.ts.map +1 -1
- package/build/types/integrations/childProcess.d.ts +2 -7
- package/build/types/integrations/childProcess.d.ts.map +1 -1
- package/build/types/integrations/fs/vendored/instrumentation.d.ts.map +1 -1
- package/build/types/integrations/http/SentryHttpInstrumentation.d.ts +6 -61
- package/build/types/integrations/http/SentryHttpInstrumentation.d.ts.map +1 -1
- package/build/types/integrations/http/httpServerIntegration.d.ts +1 -1
- package/build/types/integrations/http/httpServerSpansIntegration.d.ts +1 -9
- package/build/types/integrations/http/httpServerSpansIntegration.d.ts.map +1 -1
- package/build/types/integrations/http/index.d.ts +16 -74
- package/build/types/integrations/http/index.d.ts.map +1 -1
- package/build/types/integrations/pino.d.ts.map +1 -1
- package/build/types/integrations/tracing/hapi.d.ts +13 -0
- package/build/types/integrations/tracing/hapi.d.ts.map +1 -0
- package/build/types/integrations/tracing/index.d.ts.map +1 -1
- package/build/types/integrations/tracing/koa.d.ts +27 -0
- package/build/types/integrations/tracing/koa.d.ts.map +1 -0
- package/build/types/integrations/workerThreads.d.ts +8 -0
- package/build/types/integrations/workerThreads.d.ts.map +1 -0
- package/build/types/sdk/client.d.ts +2 -0
- package/build/types/sdk/client.d.ts.map +1 -1
- package/build/types/sdk/index.d.ts.map +1 -1
- package/build/types/sdk/initOtel.d.ts +0 -9
- package/build/types/sdk/initOtel.d.ts.map +1 -1
- package/build/types/transports/http.d.ts +1 -1
- package/build/types/transports/http.d.ts.map +1 -1
- package/build/types/types.d.ts +18 -35
- package/build/types/types.d.ts.map +1 -1
- package/package.json +7 -6
- package/build/cjs/integrations/tracing/express.js +0 -11
- package/build/cjs/integrations/tracing/express.js.map +0 -1
- package/build/cjs/integrations/tracing/fastify/index.js +0 -40
- package/build/cjs/integrations/tracing/fastify/index.js.map +0 -1
- package/build/cjs/integrations/tracing/hapi/index.js +0 -44
- package/build/cjs/integrations/tracing/hapi/index.js.map +0 -1
- package/build/cjs/integrations/tracing/koa/index.js +0 -22
- package/build/cjs/integrations/tracing/koa/index.js.map +0 -1
- package/build/cjs/integrations/tracing/redis/cache.js +0 -42
- package/build/cjs/integrations/tracing/redis/cache.js.map +0 -1
- package/build/cjs/integrations/tracing/redis/index.js +0 -34
- package/build/cjs/integrations/tracing/redis/index.js.map +0 -1
- package/build/cjs/utils/redisCache.js +0 -98
- package/build/cjs/utils/redisCache.js.map +0 -1
- package/build/esm/integrations/tracing/express.js +0 -9
- package/build/esm/integrations/tracing/express.js.map +0 -1
- package/build/esm/integrations/tracing/fastify/index.js +0 -37
- package/build/esm/integrations/tracing/fastify/index.js.map +0 -1
- package/build/esm/integrations/tracing/hapi/index.js +0 -41
- package/build/esm/integrations/tracing/hapi/index.js.map +0 -1
- package/build/esm/integrations/tracing/koa/index.js +0 -20
- package/build/esm/integrations/tracing/koa/index.js.map +0 -1
- package/build/esm/integrations/tracing/redis/cache.js +0 -39
- package/build/esm/integrations/tracing/redis/cache.js.map +0 -1
- package/build/esm/integrations/tracing/redis/index.js +0 -28
- package/build/esm/integrations/tracing/redis/index.js.map +0 -1
- package/build/esm/utils/redisCache.js +0 -89
- package/build/esm/utils/redisCache.js.map +0 -1
- package/build/types/integrations/tracing/express.d.ts +0 -6
- package/build/types/integrations/tracing/express.d.ts.map +0 -1
- package/build/types/integrations/tracing/fastify/index.d.ts +0 -115
- package/build/types/integrations/tracing/fastify/index.d.ts.map +0 -1
- package/build/types/integrations/tracing/fastify/types.d.ts +0 -33
- package/build/types/integrations/tracing/fastify/types.d.ts.map +0 -1
- package/build/types/integrations/tracing/hapi/index.d.ts +0 -29
- package/build/types/integrations/tracing/hapi/index.d.ts.map +0 -1
- package/build/types/integrations/tracing/hapi/types.d.ts +0 -166
- package/build/types/integrations/tracing/hapi/types.d.ts.map +0 -1
- package/build/types/integrations/tracing/koa/index.d.ts +0 -26
- package/build/types/integrations/tracing/koa/index.d.ts.map +0 -1
- package/build/types/integrations/tracing/redis/cache.d.ts +0 -22
- package/build/types/integrations/tracing/redis/cache.d.ts.map +0 -1
- package/build/types/integrations/tracing/redis/index.d.ts +0 -21
- package/build/types/integrations/tracing/redis/index.d.ts.map +0 -1
- package/build/types/integrations/tracing/redis/vendored/types.d.ts +0 -9
- package/build/types/integrations/tracing/redis/vendored/types.d.ts.map +0 -1
- package/build/types/utils/redisCache.d.ts +0 -17
- package/build/types/utils/redisCache.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/integrations/http/index.ts"],"sourcesContent":["import type { RequestOptions } from 'node:http';\nimport type { HttpClientRequest, HttpIncomingMessage, HttpServerResponse, Span } from '@sentry/core';\nimport { URL_FULL } from '@sentry/conventions/attributes';\nimport {\n defineIntegration,\n getRequestUrlFromClientRequest,\n hasSpansEnabled,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n stripDataUrlContent,\n} from '@sentry/core';\nimport type { NodeClient } from '../../sdk/client';\nimport type { HttpServerIntegrationOptions } from './httpServerIntegration';\nimport { httpServerIntegration } from './httpServerIntegration';\nimport type { HttpServerSpansIntegrationOptions } from './httpServerSpansIntegration';\nimport { httpServerSpansIntegration } from './httpServerSpansIntegration';\nimport type { SentryHttpInstrumentationOptions } from './SentryHttpInstrumentation';\nimport { instrumentHttpOutgoingRequests } from './SentryHttpInstrumentation';\n\nconst INTEGRATION_NAME = 'Http' as const;\n\n// TODO(v11): Consolidate all the various HTTP integration options into one,\n// and deprecate the duplicated and aliased options.\ninterface HttpOptions {\n /**\n * Whether breadcrumbs should be recorded for outgoing 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 HttpInstrumentation from OpenTelemetry is not setup,\n * only the Sentry-specific instrumentation for request isolation is applied.\n *\n * Defaults to `true` when tracing is enabled.\n */\n spans?: boolean;\n\n /**\n * Whether the integration should create [Sessions](https://docs.sentry.io/product/releases/health/#sessions) for incoming requests to track the health and crash-free rate of your releases in Sentry.\n * Read more about Release Health: https://docs.sentry.io/product/releases/health/\n *\n * Defaults to `true`.\n */\n trackIncomingRequestsAsSessions?: boolean;\n\n /**\n * Number of milliseconds until sessions tracked with `trackIncomingRequestsAsSessions` will be flushed as a session aggregate.\n *\n * Defaults to `60000` (60s).\n */\n sessionFlushingDelayMS?: number;\n\n /**\n * Whether to inject trace propagation headers (sentry-trace, baggage, traceparent) into outgoing HTTP 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 you run your own OpenTelemetry `HttpInstrumentation` and\n * want to avoid duplicate trace headers being injected by both Sentry and OpenTelemetry.\n *\n * @default `true`\n */\n tracePropagation?: boolean;\n\n /**\n * Do not capture spans or breadcrumbs for outgoing HTTP 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 * The `url` param contains the entire URL, including query string (if any), protocol, host, etc. of the outgoing request.\n * For example: `'https://someService.com/users/details?id=123'`\n *\n * The `request` param contains the original {@type RequestOptions} object used to make the outgoing request.\n * You can use it to filter on additional properties like method, headers, etc.\n */\n ignoreOutgoingRequests?: (url: string, request: RequestOptions) => boolean;\n\n /**\n * Do not capture spans for incoming HTTP requests to URLs where the given callback returns `true`.\n * Spans will be non recording if tracing is disabled.\n *\n * The `urlPath` param consists of the URL path and query string (if any) of the incoming request.\n * For example: `'/users/details?id=123'`\n *\n * The `request` param contains the original {@type IncomingMessage} object of the incoming request.\n * You can use it to filter on additional properties like method, headers, etc.\n */\n ignoreIncomingRequests?: (urlPath: string, request: HttpIncomingMessage) => boolean;\n\n /**\n * A hook that can be used to mutate the span for incoming requests.\n * This is triggered after the span is created, but before it is recorded.\n */\n incomingRequestSpanHook?: (span: Span, request: HttpIncomingMessage, response: HttpServerResponse) => void;\n\n /**\n * Whether to automatically ignore common static asset requests like favicon.ico, robots.txt, etc.\n * This helps reduce noise in your transactions.\n *\n * @default `true`\n */\n ignoreStaticAssets?: boolean;\n\n /**\n * Do not capture spans for incoming HTTP requests with the given status codes.\n * By default, spans with some 3xx and 4xx status codes are ignored (see @default).\n * Expects an array of status codes or a range of status codes, e.g. [[300,399], 404] would ignore 3xx and 404 status codes.\n *\n * @default `[[401, 404], [301, 303], [305, 399]]`\n */\n dropSpansForIncomingRequestStatusCodes?: (number | [number, number])[];\n\n /**\n * Do not capture the request body for incoming HTTP requests to URLs where the given callback returns `true`.\n * This can be useful for long running requests where the body is not needed and we want to avoid capturing it.\n *\n * @param url Contains the entire URL, including query string (if any), protocol, host, etc. of the incoming request.\n * @param request Contains the {@type RequestOptions} object used to make the incoming request.\n */\n ignoreIncomingRequestBody?: (url: string, request: RequestOptions) => boolean;\n\n /**\n * Controls the maximum size of incoming HTTP request bodies attached to events.\n *\n * Available options:\n * - 'none': No request bodies will be attached\n * - 'small': Request bodies up to 1,000 bytes will be attached\n * - 'medium': Request bodies up to 10,000 bytes will be attached (default)\n * - 'always': Request bodies will always be attached\n *\n * Note that even with 'always' setting, bodies exceeding 1MB will never be attached\n * for performance and security reasons.\n *\n * @default 'medium'\n */\n maxIncomingRequestBodySize?: 'none' | 'small' | 'medium' | 'always';\n\n /**\n * If true, do not generate spans for incoming requests at all.\n * This is used by Remix to avoid generating spans for incoming requests, as it generates its own spans.\n */\n disableIncomingRequestSpans?: boolean;\n\n /**\n * Additional instrumentation options that are passed to the underlying HttpInstrumentation.\n */\n instrumentation?: {\n requestHook?: (span: Span, req: HttpIncomingMessage | HttpClientRequest) => void;\n responseHook?: (span: Span, response: HttpIncomingMessage | HttpServerResponse) => void;\n applyCustomAttributesOnSpan?: (\n span: Span,\n request: HttpIncomingMessage | HttpClientRequest,\n response: HttpIncomingMessage | HttpServerResponse,\n ) => void;\n };\n}\n\n/**\n * The http integration instruments Node's internal http and https modules.\n * It creates breadcrumbs and spans for outgoing HTTP requests which will be attached to the currently active span.\n */\nexport const httpIntegration = defineIntegration((options: HttpOptions = {}) => {\n const spans = options.spans ?? true;\n const disableIncomingRequestSpans = options.disableIncomingRequestSpans;\n const enableServerSpans = spans && !disableIncomingRequestSpans;\n\n const serverOptions = {\n sessions: options.trackIncomingRequestsAsSessions,\n sessionFlushingDelayMS: options.sessionFlushingDelayMS,\n ignoreRequestBody: options.ignoreIncomingRequestBody,\n maxRequestBodySize: options.maxIncomingRequestBodySize,\n } satisfies HttpServerIntegrationOptions;\n\n const serverSpansOptions: HttpServerSpansIntegrationOptions = {\n ignoreIncomingRequests: options.ignoreIncomingRequests,\n ignoreStaticAssets: options.ignoreStaticAssets,\n ignoreStatusCodes: options.dropSpansForIncomingRequestStatusCodes,\n // oxlint-disable-next-line typescript/no-deprecated -- pass through the deprecated option for back-compat\n instrumentation: options.instrumentation,\n onSpanCreated: options.incomingRequestSpanHook,\n };\n\n const server = httpServerIntegration(serverOptions);\n const serverSpans = httpServerSpansIntegration(serverSpansOptions);\n\n return {\n name: INTEGRATION_NAME,\n setup(client: NodeClient) {\n const clientOptions = client.getOptions();\n\n if (enableServerSpans && hasSpansEnabled(clientOptions)) {\n serverSpans.setup(client);\n }\n },\n setupOnce() {\n server.setupOnce();\n\n const sentryHttpInstrumentationOptions: SentryHttpInstrumentationOptions = {\n breadcrumbs: options.breadcrumbs,\n spans,\n propagateTraceInOutgoingRequests: options.tracePropagation ?? true,\n // oxlint-disable-next-line typescript/no-deprecated -- deprecated alias kept until removal\n createSpansForOutgoingRequests: spans,\n ignoreOutgoingRequests: options.ignoreOutgoingRequests,\n outgoingRequestHook: (span: Span, request: HttpClientRequest) => {\n // Sanitize data URLs to prevent long base64 strings in span attributes\n const url = getRequestUrlFromClientRequest(request);\n if (url.startsWith('data:')) {\n const sanitizedUrl = stripDataUrlContent(url);\n span.updateName(`${request.method || 'GET'} ${sanitizedUrl}`);\n span.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [URL_FULL]: sanitizedUrl,\n });\n }\n options.instrumentation?.requestHook?.(span, request);\n },\n outgoingResponseHook: options.instrumentation?.responseHook,\n outgoingRequestApplyCustomAttributes: options.instrumentation?.applyCustomAttributesOnSpan,\n };\n\n // This is Sentry-specific instrumentation for outgoing request\n // breadcrumbs & trace propagation. It uses the diagnostic channels on\n // node versions that support it, falling back to monkey-patching when\n // needed.\n instrumentHttpOutgoingRequests(sentryHttpInstrumentationOptions);\n },\n processEvent(event) {\n // Always run this, even if spans are disabled\n // The reason being that e.g. the remix integration disables span\n // creation here but still wants to use the ignore status codes option\n return serverSpans.processEvent(event);\n },\n };\n});\n"],"names":["defineIntegration","httpServerIntegration","httpServerSpansIntegration","hasSpansEnabled","getRequestUrlFromClientRequest","stripDataUrlContent","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","URL_FULL","instrumentHttpOutgoingRequests"],"mappings":";;;;;;;;AAkBA,MAAM,gBAAA,GAAmB,MAAA;AA8IlB,MAAM,eAAA,GAAkBA,sBAAA,CAAkB,CAAC,OAAA,GAAuB,EAAC,KAAM;AAC9E,EAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,IAAA;AAC/B,EAAA,MAAM,8BAA8B,OAAA,CAAQ,2BAAA;AAC5C,EAAA,MAAM,iBAAA,GAAoB,SAAS,CAAC,2BAAA;AAEpC,EAAA,MAAM,aAAA,GAAgB;AAAA,IACpB,UAAU,OAAA,CAAQ,+BAAA;AAAA,IAClB,wBAAwB,OAAA,CAAQ,sBAAA;AAAA,IAChC,mBAAmB,OAAA,CAAQ,yBAAA;AAAA,IAC3B,oBAAoB,OAAA,CAAQ;AAAA,GAC9B;AAEA,EAAA,MAAM,kBAAA,GAAwD;AAAA,IAC5D,wBAAwB,OAAA,CAAQ,sBAAA;AAAA,IAChC,oBAAoB,OAAA,CAAQ,kBAAA;AAAA,IAC5B,mBAAmB,OAAA,CAAQ,sCAAA;AAAA;AAAA,IAE3B,iBAAiB,OAAA,CAAQ,eAAA;AAAA,IACzB,eAAe,OAAA,CAAQ;AAAA,GACzB;AAEA,EAAA,MAAM,MAAA,GAASC,4CAAsB,aAAa,CAAA;AAClD,EAAA,MAAM,WAAA,GAAcC,sDAA2B,kBAAkB,CAAA;AAEjE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,MAAM,MAAA,EAAoB;AACxB,MAAA,MAAM,aAAA,GAAgB,OAAO,UAAA,EAAW;AAExC,MAAA,IAAI,iBAAA,IAAqBC,oBAAA,CAAgB,aAAa,CAAA,EAAG;AACvD,QAAA,WAAA,CAAY,MAAM,MAAM,CAAA;AAAA,MAC1B;AAAA,IACF,CAAA;AAAA,IACA,SAAA,GAAY;AACV,MAAA,MAAA,CAAO,SAAA,EAAU;AAEjB,MAAA,MAAM,gCAAA,GAAqE;AAAA,QACzE,aAAa,OAAA,CAAQ,WAAA;AAAA,QACrB,KAAA;AAAA,QACA,gCAAA,EAAkC,QAAQ,gBAAA,IAAoB,IAAA;AAAA;AAAA,QAE9D,8BAAA,EAAgC,KAAA;AAAA,QAChC,wBAAwB,OAAA,CAAQ,sBAAA;AAAA,QAChC,mBAAA,EAAqB,CAAC,IAAA,EAAY,OAAA,KAA+B;AAE/D,UAAA,MAAM,GAAA,GAAMC,oCAA+B,OAAO,CAAA;AAClD,UAAA,IAAI,GAAA,CAAI,UAAA,CAAW,OAAO,CAAA,EAAG;AAC3B,YAAA,MAAM,YAAA,GAAeC,yBAAoB,GAAG,CAAA;AAC5C,YAAA,IAAA,CAAK,WAAW,CAAA,EAAG,OAAA,CAAQ,UAAU,KAAK,CAAA,CAAA,EAAI,YAAY,CAAA,CAAE,CAAA;AAC5D,YAAA,IAAA,CAAK,aAAA,CAAc;AAAA,cACjB,CAACC,qCAAgC,GAAG,KAAA;AAAA,cACpC,CAACC,mBAAQ,GAAG;AAAA,aACb,CAAA;AAAA,UACH;AACA,UAAA,OAAA,CAAQ,eAAA,EAAiB,WAAA,GAAc,IAAA,EAAM,OAAO,CAAA;AAAA,QACtD,CAAA;AAAA,QACA,oBAAA,EAAsB,QAAQ,eAAA,EAAiB,YAAA;AAAA,QAC/C,oCAAA,EAAsC,QAAQ,eAAA,EAAiB;AAAA,OACjE;AAMA,MAAAC,wDAAA,CAA+B,gCAAgC,CAAA;AAAA,IACjE,CAAA;AAAA,IACA,aAAa,KAAA,EAAO;AAIlB,MAAA,OAAO,WAAA,CAAY,aAAa,KAAK,CAAA;AAAA,IACvC;AAAA,GACF;AACF,CAAC;;;;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/integrations/http/index.ts"],"sourcesContent":["import type { ClientRequest, RequestOptions } from 'node:http';\nimport type { Span } from '@sentry/core';\nimport { URL_FULL } from '@sentry/conventions/attributes';\nimport { defineIntegration, getRequestUrlFromClientRequest, hasSpansEnabled, stripDataUrlContent } from '@sentry/core';\nimport type { NodeClient } from '../../sdk/client';\nimport type { HttpServerIntegrationOptions } from './httpServerIntegration';\nimport { httpServerIntegration } from './httpServerIntegration';\nimport type { HttpServerSpansIntegrationOptions } from './httpServerSpansIntegration';\nimport { httpServerSpansIntegration } from './httpServerSpansIntegration';\nimport type { OutgoingHttpRequestInstrumentationOptions } from './SentryHttpInstrumentation';\nimport { instrumentHttpOutgoingRequests } from './SentryHttpInstrumentation';\n\nconst INTEGRATION_NAME = 'Http' as const;\n\ninterface HttpOptions extends HttpServerIntegrationOptions, HttpServerSpansIntegrationOptions {\n /**\n * Whether breadcrumbs should be recorded for outgoing 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 HttpInstrumentation from OpenTelemetry is not setup,\n * only the Sentry-specific instrumentation for request isolation is applied.\n *\n * Defaults to `true` when tracing is enabled.\n */\n spans?: boolean;\n\n /**\n * Whether to inject trace propagation headers (sentry-trace, baggage, traceparent) into outgoing HTTP 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 you run your own OpenTelemetry `HttpInstrumentation` and\n * want to avoid duplicate trace headers being injected by both Sentry and OpenTelemetry.\n *\n * @default `true`\n */\n tracePropagation?: boolean;\n\n /**\n * Do not capture spans or breadcrumbs for outgoing HTTP 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 * The `url` param contains the entire URL, including query string (if any), protocol, host, etc. of the outgoing request.\n * For example: `'https://someService.com/users/details?id=123'`\n *\n * The `request` param contains the original {@type RequestOptions} object used to make the outgoing request.\n * You can use it to filter on additional properties like method, headers, etc.\n */\n ignoreOutgoingRequests?: (url: string, request: RequestOptions) => boolean;\n\n /**\n * If true, do not generate spans for incoming requests at all.\n * This is used by Remix to avoid generating spans for incoming requests, as it generates its own spans.\n */\n disableIncomingRequestSpans?: boolean;\n\n /**\n * Called after an outgoing request span is created.\n * Only invoked when spans are created for outgoing requests.\n */\n outgoingRequestHook?: OutgoingHttpRequestInstrumentationOptions['outgoingRequestHook'];\n\n /**\n * Called when the outgoing request receives a response.\n * Only invoked when spans are created for outgoing requests.\n */\n outgoingResponseHook?: OutgoingHttpRequestInstrumentationOptions['outgoingResponseHook'];\n\n /**\n * Called when both the outgoing request and response are available.\n * Only invoked when spans are created for outgoing requests.\n */\n outgoingRequestApplyCustomAttributes?: OutgoingHttpRequestInstrumentationOptions['outgoingRequestApplyCustomAttributes'];\n}\n\n/**\n * The http integration instruments Node's internal http and https modules.\n * It creates breadcrumbs and spans for outgoing HTTP requests which will be attached to the currently active span.\n */\nexport const httpIntegration = defineIntegration((options: HttpOptions = {}) => {\n const spans = options.spans ?? true;\n const enableServerSpans = spans && !options.disableIncomingRequestSpans;\n\n const server = httpServerIntegration(options);\n const serverSpans = httpServerSpansIntegration(options);\n\n return {\n name: INTEGRATION_NAME,\n setup(client: NodeClient) {\n const clientOptions = client.getOptions();\n\n if (enableServerSpans && hasSpansEnabled(clientOptions)) {\n serverSpans.setup(client);\n }\n },\n setupOnce() {\n server.setupOnce();\n\n const outgoingRequestOptions: OutgoingHttpRequestInstrumentationOptions = {\n breadcrumbs: options.breadcrumbs,\n spans,\n tracePropagation: options.tracePropagation ?? true,\n ignoreOutgoingRequests: options.ignoreOutgoingRequests,\n outgoingRequestHook: (span: Span, request: ClientRequest) => {\n // Sanitize data URLs to prevent long base64 strings in span attributes\n const url = getRequestUrlFromClientRequest(request);\n if (url.startsWith('data:')) {\n const sanitizedUrl = stripDataUrlContent(url);\n span.updateName(`${request.method || 'GET'} ${sanitizedUrl}`);\n span.setAttributes({\n [URL_FULL]: sanitizedUrl,\n });\n }\n options.outgoingRequestHook?.(span, request);\n },\n outgoingResponseHook: options.outgoingResponseHook,\n outgoingRequestApplyCustomAttributes: options.outgoingRequestApplyCustomAttributes,\n };\n\n // This is Sentry-specific instrumentation for outgoing request\n // breadcrumbs & trace propagation. It uses the diagnostic channels on\n // node versions that support it, falling back to monkey-patching when\n // needed.\n instrumentHttpOutgoingRequests(outgoingRequestOptions);\n },\n processEvent(event) {\n // Always run this, even if spans are disabled\n // The reason being that e.g. the remix integration disables span\n // creation here but still wants to use the ignore status codes option\n return serverSpans.processEvent(event);\n },\n };\n});\n"],"names":["defineIntegration","httpServerIntegration","httpServerSpansIntegration","hasSpansEnabled","getRequestUrlFromClientRequest","stripDataUrlContent","URL_FULL","instrumentHttpOutgoingRequests"],"mappings":";;;;;;;;AAYA,MAAM,gBAAA,GAAmB,MAAA;AAsElB,MAAM,eAAA,GAAkBA,sBAAA,CAAkB,CAAC,OAAA,GAAuB,EAAC,KAAM;AAC9E,EAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,IAAA;AAC/B,EAAA,MAAM,iBAAA,GAAoB,KAAA,IAAS,CAAC,OAAA,CAAQ,2BAAA;AAE5C,EAAA,MAAM,MAAA,GAASC,4CAAsB,OAAO,CAAA;AAC5C,EAAA,MAAM,WAAA,GAAcC,sDAA2B,OAAO,CAAA;AAEtD,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,MAAM,MAAA,EAAoB;AACxB,MAAA,MAAM,aAAA,GAAgB,OAAO,UAAA,EAAW;AAExC,MAAA,IAAI,iBAAA,IAAqBC,oBAAA,CAAgB,aAAa,CAAA,EAAG;AACvD,QAAA,WAAA,CAAY,MAAM,MAAM,CAAA;AAAA,MAC1B;AAAA,IACF,CAAA;AAAA,IACA,SAAA,GAAY;AACV,MAAA,MAAA,CAAO,SAAA,EAAU;AAEjB,MAAA,MAAM,sBAAA,GAAoE;AAAA,QACxE,aAAa,OAAA,CAAQ,WAAA;AAAA,QACrB,KAAA;AAAA,QACA,gBAAA,EAAkB,QAAQ,gBAAA,IAAoB,IAAA;AAAA,QAC9C,wBAAwB,OAAA,CAAQ,sBAAA;AAAA,QAChC,mBAAA,EAAqB,CAAC,IAAA,EAAY,OAAA,KAA2B;AAE3D,UAAA,MAAM,GAAA,GAAMC,oCAA+B,OAAO,CAAA;AAClD,UAAA,IAAI,GAAA,CAAI,UAAA,CAAW,OAAO,CAAA,EAAG;AAC3B,YAAA,MAAM,YAAA,GAAeC,yBAAoB,GAAG,CAAA;AAC5C,YAAA,IAAA,CAAK,WAAW,CAAA,EAAG,OAAA,CAAQ,UAAU,KAAK,CAAA,CAAA,EAAI,YAAY,CAAA,CAAE,CAAA;AAC5D,YAAA,IAAA,CAAK,aAAA,CAAc;AAAA,cACjB,CAACC,mBAAQ,GAAG;AAAA,aACb,CAAA;AAAA,UACH;AACA,UAAA,OAAA,CAAQ,mBAAA,GAAsB,MAAM,OAAO,CAAA;AAAA,QAC7C,CAAA;AAAA,QACA,sBAAsB,OAAA,CAAQ,oBAAA;AAAA,QAC9B,sCAAsC,OAAA,CAAQ;AAAA,OAChD;AAMA,MAAAC,wDAAA,CAA+B,sBAAsB,CAAA;AAAA,IACvD,CAAA;AAAA,IACA,aAAa,KAAA,EAAO;AAIlB,MAAA,OAAO,WAAA,CAAY,aAAa,KAAK,CAAA;AAAA,IACvC;AAAA,GACF;AACF,CAAC;;;;"}
|
|
@@ -5,7 +5,7 @@ const core = require('@sentry/core');
|
|
|
5
5
|
const debug = require('../../utils/debug.js');
|
|
6
6
|
const common = require('./common.js');
|
|
7
7
|
|
|
8
|
-
const base64WorkerScript = "
|
|
8
|
+
const base64WorkerScript = "LyohIEBzZW50cnkvbm9kZSAxMS4wLjAtYWxwaGEuMiAoYTcxYTk0MykgfCBodHRwczovL2dpdGh1Yi5jb20vZ2V0c2VudHJ5L3NlbnRyeS1qYXZhc2NyaXB0ICovCmltcG9ydHtTZXNzaW9uIGFzIGV9ZnJvbSJub2RlOmluc3BlY3Rvci9wcm9taXNlcyI7aW1wb3J0e3dvcmtlckRhdGEgYXMgdH1mcm9tIm5vZGU6d29ya2VyX3RocmVhZHMiO2NvbnN0IG49Z2xvYmFsVGhpcyxpPXt9O2NvbnN0IG89Il9fU0VOVFJZX0VSUk9SX0xPQ0FMX1ZBUklBQkxFU19fIjtjb25zdCBhPXQ7ZnVuY3Rpb24gcyguLi5lKXthLmRlYnVnJiZmdW5jdGlvbihlKXtpZighKCJjb25zb2xlImluIG4pKXJldHVybiBlKCk7Y29uc3QgdD1uLmNvbnNvbGUsbz17fSxhPU9iamVjdC5rZXlzKGkpO2EuZm9yRWFjaChlPT57Y29uc3Qgbj1pW2VdO29bZV09dFtlXSx0W2VdPW59KTt0cnl7cmV0dXJuIGUoKX1maW5hbGx5e2EuZm9yRWFjaChlPT57dFtlXT1vW2VdfSl9fSgoKT0+Y29uc29sZS5sb2coIltMb2NhbFZhcmlhYmxlcyBXb3JrZXJdIiwuLi5lKSl9YXN5bmMgZnVuY3Rpb24gYyhlLHQsbixpKXtjb25zdCBvPWF3YWl0IGUucG9zdCgiUnVudGltZS5nZXRQcm9wZXJ0aWVzIix7b2JqZWN0SWQ6dCxvd25Qcm9wZXJ0aWVzOiEwfSk7aVtuXT1vLnJlc3VsdC5maWx0ZXIoZT0+Imxlbmd0aCIhPT1lLm5hbWUmJiFpc05hTihwYXJzZUludChlLm5hbWUsMTApKSkuc29ydCgoZSx0KT0+cGFyc2VJbnQoZS5uYW1lLDEwKS1wYXJzZUludCh0Lm5hbWUsMTApKS5tYXAoZT0+ZS52YWx1ZT8udmFsdWUpfWFzeW5jIGZ1bmN0aW9uIHIoZSx0LG4saSl7Y29uc3Qgbz1hd2FpdCBlLnBvc3QoIlJ1bnRpbWUuZ2V0UHJvcGVydGllcyIse29iamVjdElkOnQsb3duUHJvcGVydGllczohMH0pO2lbbl09by5yZXN1bHQubWFwKGU9PltlLm5hbWUsZS52YWx1ZT8udmFsdWVdKS5yZWR1Y2UoKGUsW3Qsbl0pPT4oZVt0XT1uLGUpLHt9KX1mdW5jdGlvbiB1KGUsdCl7ZS52YWx1ZSYmKCJ2YWx1ZSJpbiBlLnZhbHVlP3ZvaWQgMD09PWUudmFsdWUudmFsdWV8fG51bGw9PT1lLnZhbHVlLnZhbHVlP3RbZS5uYW1lXT1gPCR7ZS52YWx1ZS52YWx1ZX0+YDp0W2UubmFtZV09ZS52YWx1ZS52YWx1ZToiZGVzY3JpcHRpb24iaW4gZS52YWx1ZSYmImZ1bmN0aW9uIiE9PWUudmFsdWUudHlwZT90W2UubmFtZV09YDwke2UudmFsdWUuZGVzY3JpcHRpb259PmA6InVuZGVmaW5lZCI9PT1lLnZhbHVlLnR5cGUmJih0W2UubmFtZV09Ijx1bmRlZmluZWQ+IikpfWFzeW5jIGZ1bmN0aW9uIGwoZSx0KXtjb25zdCBuPWF3YWl0IGUucG9zdCgiUnVudGltZS5nZXRQcm9wZXJ0aWVzIix7b2JqZWN0SWQ6dCxvd25Qcm9wZXJ0aWVzOiEwfSksaT17fTtmb3IoY29uc3QgdCBvZiBuLnJlc3VsdClpZih0LnZhbHVlPy5vYmplY3RJZCYmIkFycmF5Ij09PXQudmFsdWUuY2xhc3NOYW1lKXtjb25zdCBuPXQudmFsdWUub2JqZWN0SWQ7YXdhaXQgYyhlLG4sdC5uYW1lLGkpfWVsc2UgaWYodC52YWx1ZT8ub2JqZWN0SWQmJiJPYmplY3QiPT09dC52YWx1ZS5jbGFzc05hbWUpe2NvbnN0IG49dC52YWx1ZS5vYmplY3RJZDthd2FpdCByKGUsbix0Lm5hbWUsaSl9ZWxzZSB0LnZhbHVlJiZ1KHQsaSk7cmV0dXJuIGl9bGV0IGY7KGFzeW5jIGZ1bmN0aW9uKCl7Y29uc3QgdD1uZXcgZTt0LmNvbm5lY3RUb01haW5UaHJlYWQoKSxzKCJDb25uZWN0ZWQgdG8gbWFpbiB0aHJlYWQiKTtsZXQgbj0hMTt0Lm9uKCJEZWJ1Z2dlci5yZXN1bWVkIiwoKT0+e249ITF9KSx0Lm9uKCJEZWJ1Z2dlci5wYXVzZWQiLGU9PntuPSEwLGFzeW5jIGZ1bmN0aW9uKGUse3JlYXNvbjp0LGRhdGE6e29iamVjdElkOm59LGNhbGxGcmFtZXM6aX0pe2lmKCJleGNlcHRpb24iIT09dCYmInByb21pc2VSZWplY3Rpb24iIT09dClyZXR1cm47aWYoZj8uKCksbnVsbD09bilyZXR1cm47Y29uc3QgYT1bXTtmb3IobGV0IHQ9MDt0PGkubGVuZ3RoO3QrKyl7Y29uc3R7c2NvcGVDaGFpbjpuLGZ1bmN0aW9uTmFtZTpvLHRoaXM6c309aVt0XSxjPW4uZmluZChlPT4ibG9jYWwiPT09ZS50eXBlKSxyPSJnbG9iYWwiIT09cy5jbGFzc05hbWUmJnMuY2xhc3NOYW1lP2Ake3MuY2xhc3NOYW1lfS4ke299YDpvO2lmKHZvaWQgMD09PWM/Lm9iamVjdC5vYmplY3RJZClhW3RdPXtmdW5jdGlvbjpyfTtlbHNle2NvbnN0IG49YXdhaXQgbChlLGMub2JqZWN0Lm9iamVjdElkKTthW3RdPXtmdW5jdGlvbjpyLHZhcnM6bn19fWF3YWl0IGUucG9zdCgiUnVudGltZS5jYWxsRnVuY3Rpb25PbiIse2Z1bmN0aW9uRGVjbGFyYXRpb246YGZ1bmN0aW9uKCkgeyB0aGlzLiR7b30gPSB0aGlzLiR7b30gfHwgJHtKU09OLnN0cmluZ2lmeShhKX07IH1gLHNpbGVudDohMCxvYmplY3RJZDpufSksYXdhaXQgZS5wb3N0KCJSdW50aW1lLnJlbGVhc2VPYmplY3QiLHtvYmplY3RJZDpufSl9KHQsZS5wYXJhbXMpLnRoZW4oYXN5bmMoKT0+e24mJmF3YWl0IHQucG9zdCgiRGVidWdnZXIucmVzdW1lIil9LGFzeW5jIGU9PntuJiZhd2FpdCB0LnBvc3QoIkRlYnVnZ2VyLnJlc3VtZSIpfSl9KSxhd2FpdCB0LnBvc3QoIkRlYnVnZ2VyLmVuYWJsZSIpO2NvbnN0IGk9ITEhPT1hLmNhcHR1cmVBbGxFeGNlcHRpb25zO2lmKGF3YWl0IHQucG9zdCgiRGVidWdnZXIuc2V0UGF1c2VPbkV4Y2VwdGlvbnMiLHtzdGF0ZTppPyJhbGwiOiJ1bmNhdWdodCJ9KSxpKXtjb25zdCBlPWEubWF4RXhjZXB0aW9uc1BlclNlY29uZHx8NTA7Zj1mdW5jdGlvbihlLHQsbil7bGV0IGk9MCxvPTUsYT0wO3JldHVybiBzZXRJbnRlcnZhbCgoKT0+ezA9PT1hP2k+ZSYmKG8qPTIsbihvKSxvPjg2NDAwJiYobz04NjQwMCksYT1vKTooYS09MSwwPT09YSYmdCgpKSxpPTB9LDFlMykudW5yZWYoKSwoKT0+e2krPTF9fShlLGFzeW5jKCk9PntzKCJSYXRlLWxpbWl0IGxpZnRlZC4iKSxhd2FpdCB0LnBvc3QoIkRlYnVnZ2VyLnNldFBhdXNlT25FeGNlcHRpb25zIix7c3RhdGU6ImFsbCJ9KX0sYXN5bmMgZT0+e3MoYFJhdGUtbGltaXQgZXhjZWVkZWQuIERpc2FibGluZyBjYXB0dXJpbmcgb2YgY2F1Z2h0IGV4Y2VwdGlvbnMgZm9yICR7ZX0gc2Vjb25kcy5gKSxhd2FpdCB0LnBvc3QoIkRlYnVnZ2VyLnNldFBhdXNlT25FeGNlcHRpb25zIix7c3RhdGU6InVuY2F1Z2h0In0pfSl9fSkoKS5jYXRjaChlPT57cygiRmFpbGVkIHRvIHN0YXJ0IGRlYnVnZ2VyIixlKX0pLHNldEludGVydmFsKCgpPT57fSwxZTQpOw==";
|
|
9
9
|
function log(...args) {
|
|
10
10
|
core.debug.log("[LocalVariables]", ...args);
|
|
11
11
|
}
|
|
@@ -98,6 +98,7 @@ function onRequestCreated(config, { request }) {
|
|
|
98
98
|
const requestMethod = getRequestMethod(request.method);
|
|
99
99
|
const attributes$1 = {
|
|
100
100
|
[attributes.SENTRY_KIND]: "client",
|
|
101
|
+
[attributes.SENTRY_OP]: "http.client",
|
|
101
102
|
[attributes.HTTP_REQUEST_METHOD]: requestMethod,
|
|
102
103
|
[ATTR_HTTP_REQUEST_METHOD_ORIGINAL]: request.method,
|
|
103
104
|
[attributes.URL_FULL]: core.filterCollectedUrl(requestUrl.toString()),
|
|
@@ -105,7 +106,7 @@ function onRequestCreated(config, { request }) {
|
|
|
105
106
|
[attributes.URL_QUERY]: core.filterCollectedUrlQuery(core.getUrlQuery(requestUrl.search)),
|
|
106
107
|
[attributes.URL_FRAGMENT]: core.getUrlFragment(requestUrl.hash),
|
|
107
108
|
[attributes.URL_SCHEME]: urlScheme,
|
|
108
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.
|
|
109
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.node_fetch"
|
|
109
110
|
};
|
|
110
111
|
if (url$1.startsWith("data:")) {
|
|
111
112
|
const sanitizedUrl = core.stripDataUrlContent(url$1);
|
|
@@ -126,9 +127,6 @@ function onRequestCreated(config, { request }) {
|
|
|
126
127
|
attributes$1[attributes.USER_AGENT_ORIGINAL] = userAgent;
|
|
127
128
|
}
|
|
128
129
|
const isDataUrl = url$1.startsWith("data:");
|
|
129
|
-
if (!isDataUrl) {
|
|
130
|
-
attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] = "url";
|
|
131
|
-
}
|
|
132
130
|
const spanName = requestMethod === "_OTHER" ? "HTTP" : isDataUrl ? `${request.method || "GET"} ${core.stripDataUrlContent(url$1)}` : `${requestMethod} ${core.getSanitizedUrlString(core.parseUrl(requestUrl.toString()))}`;
|
|
133
131
|
const client = core.getClient();
|
|
134
132
|
const span = core.startInactiveSpan({
|
|
@@ -238,7 +236,7 @@ function getRequestMethod(original) {
|
|
|
238
236
|
PATCH: true,
|
|
239
237
|
DELETE: true,
|
|
240
238
|
TRACE: true,
|
|
241
|
-
// QUERY from https://datatracker.ietf.org/doc/
|
|
239
|
+
// QUERY from https://datatracker.ietf.org/doc/rfc10008/
|
|
242
240
|
QUERY: true
|
|
243
241
|
};
|
|
244
242
|
if (original.toUpperCase() in knownMethods) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"undici-instrumentation.js","sources":["../../../../src/integrations/node-fetch/undici-instrumentation.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\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 * - Refactored to use Sentry's span APIs instead of OpenTelemetry tracing APIs\n * - Dropped the OTel metrics (no MeterProvider is wired up) and the dead\n * `requireParentforSpans` code path (the SDK always passes `false`)\n * - Dropped the `@opentelemetry/instrumentation` base (undici reports via `diagnostics_channel`,\n * so no module patching was needed) — exposed as a plain `instrumentUndici()` function that the\n * integration wires up directly\n */\n\n/* eslint-disable max-lines */\n\nimport * as diagch from 'diagnostics_channel';\nimport { URL } from 'url';\n\nimport type { Span, SpanAttributes } from '@sentry/core';\nimport {\n debug,\n getClient,\n getSanitizedUrlString,\n getSpanStatusFromHttpCode,\n hasSpanStreamingEnabled,\n isTracingSuppressed,\n LRUMap,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n SPAN_STATUS_ERROR,\n startInactiveSpan,\n stripDataUrlContent,\n getUrlFragment,\n getUrlQuery,\n filterCollectedUrl,\n filterCollectedUrlQuery,\n} from '@sentry/core';\nimport { addFetchRequestBreadcrumb, addTracePropagationHeadersToFetchRequest } from '../../utils/outgoingFetchRequest';\nimport {\n HTTP_REQUEST_METHOD,\n HTTP_RESPONSE_STATUS_CODE,\n NETWORK_PEER_ADDRESS,\n NETWORK_PEER_PORT,\n SENTRY_KIND,\n SERVER_ADDRESS,\n SERVER_PORT,\n URL_FRAGMENT,\n URL_FULL,\n URL_PATH,\n URL_QUERY,\n URL_SCHEME,\n USER_AGENT_ORIGINAL,\n} from '@sentry/conventions/attributes';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport type {\n NodeFetchOptions,\n UndiciRequest,\n RequestErrorMessage,\n RequestHeadersMessage,\n RequestMessage,\n RequestTrailersMessage,\n ResponseHeadersMessage,\n} from './types';\n\n// `http.request.method_original` is not part of `@sentry/conventions`, so we keep it inline.\nconst ATTR_HTTP_REQUEST_METHOD_ORIGINAL = 'http.request.method_original';\n\n// Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug\n// We can replace this with _isInstrumented once we drop support for Node.js 18.18.0\nconst _channelSubs: Array<unknown> = [];\nconst spanFromReq = new WeakMap<UndiciRequest, Span>();\n// Whether breadcrumbs (and span-less trace propagation) should be skipped for a given request.\n// We evaluate this at request-creation time because the active context is no longer correct by the\n// time the response-headers event fires.\nconst ignoreRequestMap = new WeakMap<UndiciRequest, boolean>();\n// Caches trace-propagation decisions per URL so we don't recompute the `tracePropagationTargets` regexes per request.\nconst propagationDecisionMap = new LRUMap<string, boolean>(100);\n\n/**\n * Instrument outgoing HTTP requests made through `undici` or the global `fetch` API: emit `http.client`\n * spans, record breadcrumbs, and propagate traces into the outgoing request headers.\n *\n * Span creation is gated by the `spans` option (defaults to `true`). When spans are disabled, breadcrumbs\n * are still recorded and trace propagation headers are still injected (gated by `tracePropagation`).\n *\n * undici reports its request lifecycle via `diagnostics_channel`, so rather than patching any module we\n * subscribe to those channels directly. This is idempotent — subsequent calls are no-ops once the\n * channels have been subscribed to, and the config of the first call wins.\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\n */\nexport function instrumentUndici(config: NodeFetchOptions = {}): void {\n // Avoid duplicate subscriptions\n if (_channelSubs.length) {\n return;\n }\n\n subscribeToChannel('undici:request:create', message => onRequestCreated(config, message as RequestMessage));\n subscribeToChannel('undici:client:sendHeaders', message =>\n onRequestHeaders(config, message as RequestHeadersMessage),\n );\n subscribeToChannel('undici:request:headers', message => onResponseHeaders(config, message as ResponseHeadersMessage));\n subscribeToChannel('undici:request:trailers', message => onDone(message as RequestTrailersMessage));\n subscribeToChannel('undici:request:error', message => onError(message as RequestErrorMessage));\n}\n\n/** Replaces OTel's `safeExecuteInTheMiddle`: run `fn`, route any error to `onError`, and swallow it. */\nfunction safeExecute<T>(fn: () => T, onError: (error: unknown) => void): T | undefined {\n try {\n return fn();\n } catch (error) {\n onError(error);\n return undefined;\n }\n}\n\nfunction subscribeToChannel(\n diagnosticChannel: string,\n onMessage: (message: unknown, name: string | symbol) => void,\n): void {\n _channelSubs.push(diagch.subscribe?.(diagnosticChannel, onMessage));\n}\n\nfunction parseRequestHeaders(request: UndiciRequest): Map<string, string | string[]> {\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\nfunction onRequestCreated(config: NodeFetchOptions, { request }: RequestMessage): void {\n const url = getAbsoluteUrl(request.origin, request.path);\n\n const ignoredByCallback = safeExecute(\n () => !!config.ignoreOutgoingRequests?.(url),\n e => e && DEBUG_BUILD && debug.error('caught ignoreOutgoingRequests error: ', e),\n );\n\n // Breadcrumbs & span-less trace propagation are additionally skipped when tracing is suppressed.\n // We store this here because the active context is no longer correct in later channel events.\n const ignoreForBreadcrumbs = isTracingSuppressed() || !!ignoredByCallback;\n ignoreRequestMap.set(request, ignoreForBreadcrumbs);\n\n // When spans are disabled we do not create a span, but we still inject trace propagation headers\n // directly (unless disabled via `tracePropagation`).\n if (!config.spans) {\n if (config.tracePropagation !== false && !ignoreForBreadcrumbs) {\n addTracePropagationHeadersToFetchRequest(request, propagationDecisionMap);\n }\n return;\n }\n\n // Ignore span creation if:\n // - the outgoing request is ignored via config\n // - method is 'CONNECT'\n if (request.method === 'CONNECT' || ignoredByCallback) {\n return;\n }\n\n let requestUrl;\n try {\n requestUrl = new URL(request.path, request.origin);\n } catch (err) {\n DEBUG_BUILD && debug.warn('could not determine url.full:', err);\n // Skip instrumenting this request.\n return;\n }\n\n const urlScheme = requestUrl.protocol.replace(':', '');\n const requestMethod = getRequestMethod(request.method);\n const attributes: SpanAttributes = {\n [SENTRY_KIND]: 'client',\n [HTTP_REQUEST_METHOD]: requestMethod,\n [ATTR_HTTP_REQUEST_METHOD_ORIGINAL]: request.method,\n [URL_FULL]: filterCollectedUrl(requestUrl.toString()),\n [URL_PATH]: requestUrl.pathname,\n [URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(requestUrl.search)),\n [URL_FRAGMENT]: getUrlFragment(requestUrl.hash),\n [URL_SCHEME]: urlScheme,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.node_fetch',\n };\n\n // Sanitize data URLs to prevent long base64 strings in span attributes\n if (url.startsWith('data:')) {\n const sanitizedUrl = stripDataUrlContent(url);\n attributes[URL_FULL] = sanitizedUrl;\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME] = `${request.method || 'GET'} ${sanitizedUrl}`;\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[SERVER_ADDRESS] = serverAddress;\n if (serverPort && !isNaN(Number(serverPort))) {\n attributes[SERVER_PORT] = Number(serverPort);\n }\n\n // Get user agent from headers\n const headersMap = 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[USER_AGENT_ORIGINAL] = userAgent;\n }\n\n // Outside of span streaming, only record an `http.client` span when it has a parent. An orphan\n // one (no local parent) is left to the server for the downstream sampling decision: `onlyIfParent`\n // still creates a non-recording span so trace propagation headers are injected, but it isn't\n // emitted as a standalone transaction. This rule also lives in `SentrySampler`, but that only runs\n // when an OpenTelemetry SDK tracer provider is set up, so we enforce it here too, which covers\n // SDKs that don't use an OpenTelemetry tracer provider at all.\n const isDataUrl = url.startsWith('data:');\n if (!isDataUrl) {\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] = 'url';\n }\n const spanName =\n requestMethod === '_OTHER'\n ? 'HTTP'\n : isDataUrl\n ? `${request.method || 'GET'} ${stripDataUrlContent(url)}`\n : `${requestMethod} ${getSanitizedUrlString(parseUrl(requestUrl.toString()))}`;\n\n const client = getClient();\n const span = startInactiveSpan({\n name: spanName,\n attributes,\n onlyIfParent: !client || !hasSpanStreamingEnabled(client),\n });\n\n // Execute the request hook if defined\n safeExecute(\n () => config.requestHook?.(span, request),\n e => e && DEBUG_BUILD && debug.error('caught requestHook error: ', e),\n );\n\n // Context propagation goes last so no hook can tamper the propagation headers.\n // We propagate the trace data of the freshly created client span (not the active parent span)\n // so downstream services are parented to the http.client span, matching the upstream behavior.\n // This also de-duplicates against any trace headers the user set manually (e.g. via `getTraceData()`).\n addTracePropagationHeadersToFetchRequest(request, propagationDecisionMap, span);\n\n spanFromReq.set(request, span);\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\nfunction onRequestHeaders(config: NodeFetchOptions, { request, socket }: RequestHeadersMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n const { remoteAddress, remotePort } = socket;\n const spanAttributes: SpanAttributes = {\n [NETWORK_PEER_ADDRESS]: remoteAddress,\n [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 = 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\nfunction onResponseHeaders(config: NodeFetchOptions, { request, response }: ResponseHeadersMessage): void {\n // Breadcrumbs are recorded independently of spans, so this runs even when span creation is disabled.\n const breadcrumbsEnabled = config.breadcrumbs !== false;\n if (breadcrumbsEnabled && !ignoreRequestMap.get(request)) {\n addFetchRequestBreadcrumb(request, response);\n }\n\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n const spanAttributes: SpanAttributes = {\n [HTTP_RESPONSE_STATUS_CODE]: response.statusCode,\n };\n\n // Execute the response hook if defined\n safeExecute(\n () => config.responseHook?.(span, { request, response }),\n e => e && DEBUG_BUILD && debug.error('caught responseHook error: ', e),\n );\n\n if (config.headersToSpanAttributes?.responseHeaders) {\n const headersToAttribs = new Set<string>();\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\n // Resolve the HTTP status code to a Sentry span status here (like the raw http client/server\n // instrumentation does) instead of setting a bare error and deferring to downstream inference.\n // The SentryTracerProvider's status finalization reads the already-stringified span status, which\n // can no longer be inferred back to `not_found` etc. the way the OpenTelemetry SDK exporter's\n // `mapStatus` does from the raw `{ code, message }`.\n if (response.statusCode >= 400) {\n span.setStatus(getSpanStatusFromHttpCode(response.statusCode));\n }\n}\n\n// This is the last event we receive if the request went without any errors\nfunction onDone({ request }: RequestTrailersMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n span.end();\n spanFromReq.delete(request);\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.\nfunction onError({ request, error }: RequestErrorMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\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.setStatus({\n code: SPAN_STATUS_ERROR,\n message: error.message,\n });\n span.end();\n spanFromReq.delete(request);\n}\n\nfunction 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// 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"],"names":["LRUMap","onError","url","DEBUG_BUILD","debug","isTracingSuppressed","addTracePropagationHeadersToFetchRequest","URL","attributes","SENTRY_KIND","HTTP_REQUEST_METHOD","URL_FULL","filterCollectedUrl","URL_PATH","URL_QUERY","filterCollectedUrlQuery","getUrlQuery","URL_FRAGMENT","getUrlFragment","URL_SCHEME","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","stripDataUrlContent","SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME","SERVER_ADDRESS","SERVER_PORT","USER_AGENT_ORIGINAL","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","getSanitizedUrlString","parseUrl","getClient","startInactiveSpan","hasSpanStreamingEnabled","NETWORK_PEER_ADDRESS","NETWORK_PEER_PORT","addFetchRequestBreadcrumb","HTTP_RESPONSE_STATUS_CODE","getSpanStatusFromHttpCode","SPAN_STATUS_ERROR"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"undici-instrumentation.js","sources":["../../../../src/integrations/node-fetch/undici-instrumentation.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\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 * - Refactored to use Sentry's span APIs instead of OpenTelemetry tracing APIs\n * - Dropped the OTel metrics (no MeterProvider is wired up) and the dead\n * `requireParentforSpans` code path (the SDK always passes `false`)\n * - Dropped the `@opentelemetry/instrumentation` base (undici reports via `diagnostics_channel`,\n * so no module patching was needed) — exposed as a plain `instrumentUndici()` function that the\n * integration wires up directly\n */\n\n/* eslint-disable max-lines */\n\nimport * as diagch from 'diagnostics_channel';\nimport { URL } from 'url';\n\nimport type { Span, SpanAttributes } from '@sentry/core';\nimport {\n debug,\n getClient,\n getSanitizedUrlString,\n getSpanStatusFromHttpCode,\n hasSpanStreamingEnabled,\n isTracingSuppressed,\n LRUMap,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startInactiveSpan,\n stripDataUrlContent,\n getUrlFragment,\n getUrlQuery,\n filterCollectedUrl,\n filterCollectedUrlQuery,\n} from '@sentry/core';\nimport { addFetchRequestBreadcrumb, addTracePropagationHeadersToFetchRequest } from '../../utils/outgoingFetchRequest';\nimport {\n HTTP_REQUEST_METHOD,\n HTTP_RESPONSE_STATUS_CODE,\n NETWORK_PEER_ADDRESS,\n NETWORK_PEER_PORT,\n SENTRY_KIND,\n SENTRY_OP,\n SERVER_ADDRESS,\n SERVER_PORT,\n URL_FRAGMENT,\n URL_FULL,\n URL_PATH,\n URL_QUERY,\n URL_SCHEME,\n USER_AGENT_ORIGINAL,\n} from '@sentry/conventions/attributes';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport type {\n NodeFetchOptions,\n UndiciRequest,\n RequestErrorMessage,\n RequestHeadersMessage,\n RequestMessage,\n RequestTrailersMessage,\n ResponseHeadersMessage,\n} from './types';\n\n// `http.request.method_original` is not part of `@sentry/conventions`, so we keep it inline.\nconst ATTR_HTTP_REQUEST_METHOD_ORIGINAL = 'http.request.method_original';\n\n// Keep ref to avoid https://github.com/nodejs/node/issues/42170 bug\n// We can replace this with _isInstrumented once we drop support for Node.js 18.18.0\nconst _channelSubs: Array<unknown> = [];\nconst spanFromReq = new WeakMap<UndiciRequest, Span>();\n// Whether breadcrumbs (and span-less trace propagation) should be skipped for a given request.\n// We evaluate this at request-creation time because the active context is no longer correct by the\n// time the response-headers event fires.\nconst ignoreRequestMap = new WeakMap<UndiciRequest, boolean>();\n// Caches trace-propagation decisions per URL so we don't recompute the `tracePropagationTargets` regexes per request.\nconst propagationDecisionMap = new LRUMap<string, boolean>(100);\n\n/**\n * Instrument outgoing HTTP requests made through `undici` or the global `fetch` API: emit `http.client`\n * spans, record breadcrumbs, and propagate traces into the outgoing request headers.\n *\n * Span creation is gated by the `spans` option (defaults to `true`). When spans are disabled, breadcrumbs\n * are still recorded and trace propagation headers are still injected (gated by `tracePropagation`).\n *\n * undici reports its request lifecycle via `diagnostics_channel`, so rather than patching any module we\n * subscribe to those channels directly. This is idempotent — subsequent calls are no-ops once the\n * channels have been subscribed to, and the config of the first call wins.\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\n */\nexport function instrumentUndici(config: NodeFetchOptions = {}): void {\n // Avoid duplicate subscriptions\n if (_channelSubs.length) {\n return;\n }\n\n subscribeToChannel('undici:request:create', message => onRequestCreated(config, message as RequestMessage));\n subscribeToChannel('undici:client:sendHeaders', message =>\n onRequestHeaders(config, message as RequestHeadersMessage),\n );\n subscribeToChannel('undici:request:headers', message => onResponseHeaders(config, message as ResponseHeadersMessage));\n subscribeToChannel('undici:request:trailers', message => onDone(message as RequestTrailersMessage));\n subscribeToChannel('undici:request:error', message => onError(message as RequestErrorMessage));\n}\n\n/** Replaces OTel's `safeExecuteInTheMiddle`: run `fn`, route any error to `onError`, and swallow it. */\nfunction safeExecute<T>(fn: () => T, onError: (error: unknown) => void): T | undefined {\n try {\n return fn();\n } catch (error) {\n onError(error);\n return undefined;\n }\n}\n\nfunction subscribeToChannel(\n diagnosticChannel: string,\n onMessage: (message: unknown, name: string | symbol) => void,\n): void {\n _channelSubs.push(diagch.subscribe?.(diagnosticChannel, onMessage));\n}\n\nfunction parseRequestHeaders(request: UndiciRequest): Map<string, string | string[]> {\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\nfunction onRequestCreated(config: NodeFetchOptions, { request }: RequestMessage): void {\n const url = getAbsoluteUrl(request.origin, request.path);\n\n const ignoredByCallback = safeExecute(\n () => !!config.ignoreOutgoingRequests?.(url),\n e => e && DEBUG_BUILD && debug.error('caught ignoreOutgoingRequests error: ', e),\n );\n\n // Breadcrumbs & span-less trace propagation are additionally skipped when tracing is suppressed.\n // We store this here because the active context is no longer correct in later channel events.\n const ignoreForBreadcrumbs = isTracingSuppressed() || !!ignoredByCallback;\n ignoreRequestMap.set(request, ignoreForBreadcrumbs);\n\n // When spans are disabled we do not create a span, but we still inject trace propagation headers\n // directly (unless disabled via `tracePropagation`).\n if (!config.spans) {\n if (config.tracePropagation !== false && !ignoreForBreadcrumbs) {\n addTracePropagationHeadersToFetchRequest(request, propagationDecisionMap);\n }\n return;\n }\n\n // Ignore span creation if:\n // - the outgoing request is ignored via config\n // - method is 'CONNECT'\n if (request.method === 'CONNECT' || ignoredByCallback) {\n return;\n }\n\n let requestUrl;\n try {\n requestUrl = new URL(request.path, request.origin);\n } catch (err) {\n DEBUG_BUILD && debug.warn('could not determine url.full:', err);\n // Skip instrumenting this request.\n return;\n }\n\n const urlScheme = requestUrl.protocol.replace(':', '');\n const requestMethod = getRequestMethod(request.method);\n const attributes: SpanAttributes = {\n [SENTRY_KIND]: 'client',\n [SENTRY_OP]: 'http.client',\n [HTTP_REQUEST_METHOD]: requestMethod,\n [ATTR_HTTP_REQUEST_METHOD_ORIGINAL]: request.method,\n [URL_FULL]: filterCollectedUrl(requestUrl.toString()),\n [URL_PATH]: requestUrl.pathname,\n [URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(requestUrl.search)),\n [URL_FRAGMENT]: getUrlFragment(requestUrl.hash),\n [URL_SCHEME]: urlScheme,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.node_fetch',\n };\n\n // Sanitize data URLs to prevent long base64 strings in span attributes\n if (url.startsWith('data:')) {\n const sanitizedUrl = stripDataUrlContent(url);\n attributes[URL_FULL] = sanitizedUrl;\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME] = `${request.method || 'GET'} ${sanitizedUrl}`;\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[SERVER_ADDRESS] = serverAddress;\n if (serverPort && !isNaN(Number(serverPort))) {\n attributes[SERVER_PORT] = Number(serverPort);\n }\n\n // Get user agent from headers\n const headersMap = 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[USER_AGENT_ORIGINAL] = userAgent;\n }\n\n // Outside of span streaming, only record an `http.client` span when it has a parent. An orphan\n // one (no local parent) is left to the server for the downstream sampling decision: `onlyIfParent`\n // still creates a non-recording span so trace propagation headers are injected, but it isn't\n // emitted as a standalone transaction. This rule also lives in `SentrySampler`, but that only runs\n // when an OpenTelemetry SDK tracer provider is set up, so we enforce it here too, which covers\n // SDKs that don't use an OpenTelemetry tracer provider at all.\n const isDataUrl = url.startsWith('data:');\n const spanName =\n requestMethod === '_OTHER'\n ? 'HTTP'\n : isDataUrl\n ? `${request.method || 'GET'} ${stripDataUrlContent(url)}`\n : `${requestMethod} ${getSanitizedUrlString(parseUrl(requestUrl.toString()))}`;\n\n const client = getClient();\n const span = startInactiveSpan({\n name: spanName,\n attributes,\n onlyIfParent: !client || !hasSpanStreamingEnabled(client),\n });\n\n // Execute the request hook if defined\n safeExecute(\n () => config.requestHook?.(span, request),\n e => e && DEBUG_BUILD && debug.error('caught requestHook error: ', e),\n );\n\n // Context propagation goes last so no hook can tamper the propagation headers.\n // We propagate the trace data of the freshly created client span (not the active parent span)\n // so downstream services are parented to the http.client span, matching the upstream behavior.\n // This also de-duplicates against any trace headers the user set manually (e.g. via `getTraceData()`).\n addTracePropagationHeadersToFetchRequest(request, propagationDecisionMap, span);\n\n spanFromReq.set(request, span);\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\nfunction onRequestHeaders(config: NodeFetchOptions, { request, socket }: RequestHeadersMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n const { remoteAddress, remotePort } = socket;\n const spanAttributes: SpanAttributes = {\n [NETWORK_PEER_ADDRESS]: remoteAddress,\n [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 = 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\nfunction onResponseHeaders(config: NodeFetchOptions, { request, response }: ResponseHeadersMessage): void {\n // Breadcrumbs are recorded independently of spans, so this runs even when span creation is disabled.\n const breadcrumbsEnabled = config.breadcrumbs !== false;\n if (breadcrumbsEnabled && !ignoreRequestMap.get(request)) {\n addFetchRequestBreadcrumb(request, response);\n }\n\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n const spanAttributes: SpanAttributes = {\n [HTTP_RESPONSE_STATUS_CODE]: response.statusCode,\n };\n\n // Execute the response hook if defined\n safeExecute(\n () => config.responseHook?.(span, { request, response }),\n e => e && DEBUG_BUILD && debug.error('caught responseHook error: ', e),\n );\n\n if (config.headersToSpanAttributes?.responseHeaders) {\n const headersToAttribs = new Set<string>();\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\n // Resolve the HTTP status code to a Sentry span status here (like the raw http client/server\n // instrumentation does) instead of setting a bare error and deferring to downstream inference.\n // The SentryTracerProvider's status finalization reads the already-stringified span status, which\n // can no longer be inferred back to `not_found` etc. the way the OpenTelemetry SDK exporter's\n // `mapStatus` does from the raw `{ code, message }`.\n if (response.statusCode >= 400) {\n span.setStatus(getSpanStatusFromHttpCode(response.statusCode));\n }\n}\n\n// This is the last event we receive if the request went without any errors\nfunction onDone({ request }: RequestTrailersMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\n\n span.end();\n spanFromReq.delete(request);\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.\nfunction onError({ request, error }: RequestErrorMessage): void {\n const span = spanFromReq.get(request);\n\n if (!span) {\n return;\n }\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.setStatus({\n code: SPAN_STATUS_ERROR,\n message: error.message,\n });\n span.end();\n spanFromReq.delete(request);\n}\n\nfunction 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/rfc10008/\n QUERY: true,\n };\n\n if (original.toUpperCase() in knownMethods) {\n return original.toUpperCase();\n }\n\n return '_OTHER';\n}\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"],"names":["LRUMap","onError","url","DEBUG_BUILD","debug","isTracingSuppressed","addTracePropagationHeadersToFetchRequest","URL","attributes","SENTRY_KIND","SENTRY_OP","HTTP_REQUEST_METHOD","URL_FULL","filterCollectedUrl","URL_PATH","URL_QUERY","filterCollectedUrlQuery","getUrlQuery","URL_FRAGMENT","getUrlFragment","URL_SCHEME","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","stripDataUrlContent","SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME","SERVER_ADDRESS","SERVER_PORT","USER_AGENT_ORIGINAL","getSanitizedUrlString","parseUrl","getClient","startInactiveSpan","hasSpanStreamingEnabled","NETWORK_PEER_ADDRESS","NETWORK_PEER_PORT","addFetchRequestBreadcrumb","HTTP_RESPONSE_STATUS_CODE","getSpanStatusFromHttpCode","SPAN_STATUS_ERROR"],"mappings":"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"}
|
|
@@ -35,8 +35,7 @@ const _pinoIntegration = core.defineIntegration((userOptions = {}) => {
|
|
|
35
35
|
}
|
|
36
36
|
return {
|
|
37
37
|
name: "Pino",
|
|
38
|
-
setup: (
|
|
39
|
-
const enableLogs = !!client.getOptions().enableLogs;
|
|
38
|
+
setup: () => {
|
|
40
39
|
const integratedChannel = diagnosticsChannel.tracingChannel("pino_asJson");
|
|
41
40
|
function onPinoStart(self, args, result) {
|
|
42
41
|
if (!shouldTrackLogger(self)) {
|
|
@@ -47,7 +46,7 @@ const _pinoIntegration = core.defineIntegration((userOptions = {}) => {
|
|
|
47
46
|
const level = self?.levels?.labels?.[levelNumber] || "info";
|
|
48
47
|
const messageKey = getPinoKey(self, "pino.messageKey", "msg");
|
|
49
48
|
const logMessage = message || resultObj?.[messageKey] || "";
|
|
50
|
-
if (
|
|
49
|
+
if (options.log.levels.includes(level)) {
|
|
51
50
|
const attributes = {
|
|
52
51
|
...resultObj,
|
|
53
52
|
"sentry.origin": "auto.log.pino",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pino.js","sources":["../../../src/integrations/pino.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, LogSeverityLevel } from '@sentry/core';\nimport {\n _INTERNAL_captureLog,\n addExceptionMechanism,\n captureException,\n captureMessage,\n defineIntegration,\n isObjectLike,\n severityLevelFromString,\n withScope,\n} from '@sentry/core';\n\nconst SENTRY_TRACK_SYMBOL = Symbol('sentry-track-pino-logger');\n\ntype LevelMapping = {\n // Fortunately pino uses the same levels as Sentry\n labels: { [level: number]: LogSeverityLevel };\n};\n\ntype Pino = {\n [key: symbol]: unknown;\n levels: LevelMapping;\n [SENTRY_TRACK_SYMBOL]?: 'track' | 'ignore';\n};\n\n/**\n * Gets a custom Pino key from a logger instance by searching for the symbol.\n * Pino uses non-global symbols like Symbol('pino.messageKey'): https://github.com/pinojs/pino/blob/8a816c0b1f72de5ae9181f3bb402109b66f7d812/lib/symbols.js\n */\nfunction getPinoKey(logger: Pino, symbolName: string, defaultKey: string): string {\n const symbols = Object.getOwnPropertySymbols(logger);\n const symbolString = `Symbol(${symbolName})`;\n for (const sym of symbols) {\n if (sym.toString() === symbolString) {\n const value = logger[sym];\n return typeof value === 'string' ? value : defaultKey;\n }\n }\n return defaultKey;\n}\n\ntype MergeObject = {\n [key: string]: unknown;\n err?: Error;\n};\n\ntype PinoHookArgs = [MergeObject, string, number];\n\ntype PinoOptions = {\n /**\n * Automatically instrument all Pino loggers.\n *\n * When set to `false`, only loggers marked with `pinoIntegration.trackLogger(logger)` will be captured.\n *\n * @default true\n */\n autoInstrument: boolean;\n /**\n * Options to enable capturing of error events.\n */\n error: {\n /**\n * Levels that trigger capturing of events.\n *\n * @default []\n */\n levels: LogSeverityLevel[];\n /**\n * By default, Sentry will mark captured errors as handled.\n * Set this to `false` if you want to mark them as unhandled instead.\n *\n * @default true\n */\n handled: boolean;\n };\n /**\n * Options to enable capturing of logs.\n */\n log: {\n /**\n * Levels that trigger capturing of logs.\n *\n * @default [\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\"]\n */\n levels: LogSeverityLevel[];\n };\n};\n\nconst DEFAULT_OPTIONS: PinoOptions = {\n autoInstrument: true,\n error: { levels: [], handled: true },\n log: { levels: ['trace', 'debug', 'info', 'warn', 'error', 'fatal'] },\n};\n\ntype DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? Partial<T[P]> : T[P];\n};\n\ntype PinoResult = {\n level?: string;\n time?: string;\n pid?: number;\n hostname?: string;\n} & Record<string, unknown>;\n\nfunction stripIgnoredFields(result: PinoResult): PinoResult {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { level, time, pid, hostname, ...rest } = result;\n return rest;\n}\n\nconst _pinoIntegration = defineIntegration((userOptions: DeepPartial<PinoOptions> = {}) => {\n const options: PinoOptions = {\n autoInstrument: userOptions.autoInstrument !== false,\n error: { ...DEFAULT_OPTIONS.error, ...userOptions.error },\n log: { ...DEFAULT_OPTIONS.log, ...userOptions.log },\n };\n\n function shouldTrackLogger(logger: Pino): boolean {\n const override = logger[SENTRY_TRACK_SYMBOL];\n return override === 'track' || (override !== 'ignore' && options.autoInstrument);\n }\n\n return {\n name: 'Pino',\n setup: client => {\n const enableLogs = !!client.getOptions().enableLogs;\n\n const integratedChannel = diagnosticsChannel.tracingChannel('pino_asJson');\n\n function onPinoStart(self: Pino, args: PinoHookArgs, result: PinoResult): void {\n if (!shouldTrackLogger(self)) {\n return;\n }\n\n const resultObj = stripIgnoredFields(result);\n\n const [captureObj, message, levelNumber] = args;\n const level = self?.levels?.labels?.[levelNumber] || 'info';\n const messageKey = getPinoKey(self, 'pino.messageKey', 'msg');\n const logMessage = message || (resultObj?.[messageKey] as string | undefined) || '';\n\n if (enableLogs && options.log.levels.includes(level)) {\n const attributes: Record<string, unknown> = {\n ...resultObj,\n 'sentry.origin': 'auto.log.pino',\n 'pino.logger.level': levelNumber,\n };\n\n _INTERNAL_captureLog({ level, message: logMessage, attributes });\n }\n\n if (options.error.levels.includes(level)) {\n const errorKey = getPinoKey(self, 'pino.errorKey', 'err');\n\n // Attach the log message and remaining log fields (e.g. child logger\n // bindings, merge object fields) to the event. The serialized error is\n // excluded since it is captured as the event exception itself.\n const pinoContext: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(resultObj)) {\n if (key !== errorKey && key !== messageKey) {\n pinoContext[key] = value;\n }\n }\n if (logMessage) {\n pinoContext[messageKey] = logMessage;\n }\n\n const captureContext = {\n level: severityLevelFromString(level),\n contexts: { pino: pinoContext },\n };\n\n withScope(scope => {\n scope.addEventProcessor(event => {\n event.logger = 'pino';\n\n addExceptionMechanism(event, {\n handled: options.error.handled,\n type: 'auto.log.pino',\n });\n\n return event;\n });\n\n const error = captureObj[errorKey];\n if (error) {\n captureException(error, captureContext);\n return;\n }\n\n captureMessage(logMessage, captureContext);\n });\n }\n }\n\n integratedChannel.end.subscribe(data => {\n const {\n instance,\n arguments: args,\n result,\n } = data as { instance: Pino; arguments: PinoHookArgs; result: string };\n onPinoStart(instance, args, JSON.parse(result));\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Integration for Pino logging library.\n * Captures Pino logs as Sentry logs and optionally captures some log levels as events.\n *\n * By default, all Pino loggers will be captured. To ignore a specific logger, use `pinoIntegration.untrackLogger(logger)`.\n *\n * If you disable automatic instrumentation with `autoInstrument: false`, you can mark specific loggers to be tracked with `pinoIntegration.trackLogger(logger)`.\n *\n * Requires Pino >=v8.0.0\n */\nexport const pinoIntegration = Object.assign(_pinoIntegration, {\n trackLogger(logger: unknown): void {\n if (isObjectLike(logger) && 'levels' in logger) {\n (logger as Pino)[SENTRY_TRACK_SYMBOL] = 'track';\n }\n },\n untrackLogger(logger: unknown): void {\n if (isObjectLike(logger) && 'levels' in logger) {\n (logger as Pino)[SENTRY_TRACK_SYMBOL] = 'ignore';\n }\n },\n});\n"],"names":["defineIntegration","_INTERNAL_captureLog","severityLevelFromString","withScope","addExceptionMechanism","captureException","captureMessage","isObjectLike"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pino.js","sources":["../../../src/integrations/pino.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, LogSeverityLevel } from '@sentry/core';\nimport {\n _INTERNAL_captureLog,\n addExceptionMechanism,\n captureException,\n captureMessage,\n defineIntegration,\n isObjectLike,\n severityLevelFromString,\n withScope,\n} from '@sentry/core';\n\nconst SENTRY_TRACK_SYMBOL = Symbol('sentry-track-pino-logger');\n\ntype LevelMapping = {\n // Fortunately pino uses the same levels as Sentry\n labels: { [level: number]: LogSeverityLevel };\n};\n\ntype Pino = {\n [key: symbol]: unknown;\n levels: LevelMapping;\n [SENTRY_TRACK_SYMBOL]?: 'track' | 'ignore';\n};\n\n/**\n * Gets a custom Pino key from a logger instance by searching for the symbol.\n * Pino uses non-global symbols like Symbol('pino.messageKey'): https://github.com/pinojs/pino/blob/8a816c0b1f72de5ae9181f3bb402109b66f7d812/lib/symbols.js\n */\nfunction getPinoKey(logger: Pino, symbolName: string, defaultKey: string): string {\n const symbols = Object.getOwnPropertySymbols(logger);\n const symbolString = `Symbol(${symbolName})`;\n for (const sym of symbols) {\n if (sym.toString() === symbolString) {\n const value = logger[sym];\n return typeof value === 'string' ? value : defaultKey;\n }\n }\n return defaultKey;\n}\n\ntype MergeObject = {\n [key: string]: unknown;\n err?: Error;\n};\n\ntype PinoHookArgs = [MergeObject, string, number];\n\ntype PinoOptions = {\n /**\n * Automatically instrument all Pino loggers.\n *\n * When set to `false`, only loggers marked with `pinoIntegration.trackLogger(logger)` will be captured.\n *\n * @default true\n */\n autoInstrument: boolean;\n /**\n * Options to enable capturing of error events.\n */\n error: {\n /**\n * Levels that trigger capturing of events.\n *\n * @default []\n */\n levels: LogSeverityLevel[];\n /**\n * By default, Sentry will mark captured errors as handled.\n * Set this to `false` if you want to mark them as unhandled instead.\n *\n * @default true\n */\n handled: boolean;\n };\n /**\n * Options to enable capturing of logs.\n */\n log: {\n /**\n * Levels that trigger capturing of logs.\n *\n * @default [\"trace\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\"]\n */\n levels: LogSeverityLevel[];\n };\n};\n\nconst DEFAULT_OPTIONS: PinoOptions = {\n autoInstrument: true,\n error: { levels: [], handled: true },\n log: { levels: ['trace', 'debug', 'info', 'warn', 'error', 'fatal'] },\n};\n\ntype DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? Partial<T[P]> : T[P];\n};\n\ntype PinoResult = {\n level?: string;\n time?: string;\n pid?: number;\n hostname?: string;\n} & Record<string, unknown>;\n\nfunction stripIgnoredFields(result: PinoResult): PinoResult {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { level, time, pid, hostname, ...rest } = result;\n return rest;\n}\n\nconst _pinoIntegration = defineIntegration((userOptions: DeepPartial<PinoOptions> = {}) => {\n const options: PinoOptions = {\n autoInstrument: userOptions.autoInstrument !== false,\n error: { ...DEFAULT_OPTIONS.error, ...userOptions.error },\n log: { ...DEFAULT_OPTIONS.log, ...userOptions.log },\n };\n\n function shouldTrackLogger(logger: Pino): boolean {\n const override = logger[SENTRY_TRACK_SYMBOL];\n return override === 'track' || (override !== 'ignore' && options.autoInstrument);\n }\n\n return {\n name: 'Pino',\n setup: () => {\n const integratedChannel = diagnosticsChannel.tracingChannel('pino_asJson');\n\n function onPinoStart(self: Pino, args: PinoHookArgs, result: PinoResult): void {\n if (!shouldTrackLogger(self)) {\n return;\n }\n\n const resultObj = stripIgnoredFields(result);\n\n const [captureObj, message, levelNumber] = args;\n const level = self?.levels?.labels?.[levelNumber] || 'info';\n const messageKey = getPinoKey(self, 'pino.messageKey', 'msg');\n const logMessage = message || (resultObj?.[messageKey] as string | undefined) || '';\n\n if (options.log.levels.includes(level)) {\n const attributes: Record<string, unknown> = {\n ...resultObj,\n 'sentry.origin': 'auto.log.pino',\n 'pino.logger.level': levelNumber,\n };\n\n _INTERNAL_captureLog({ level, message: logMessage, attributes });\n }\n\n if (options.error.levels.includes(level)) {\n const errorKey = getPinoKey(self, 'pino.errorKey', 'err');\n\n // Attach the log message and remaining log fields (e.g. child logger\n // bindings, merge object fields) to the event. The serialized error is\n // excluded since it is captured as the event exception itself.\n const pinoContext: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(resultObj)) {\n if (key !== errorKey && key !== messageKey) {\n pinoContext[key] = value;\n }\n }\n if (logMessage) {\n pinoContext[messageKey] = logMessage;\n }\n\n const captureContext = {\n level: severityLevelFromString(level),\n contexts: { pino: pinoContext },\n };\n\n withScope(scope => {\n scope.addEventProcessor(event => {\n event.logger = 'pino';\n\n addExceptionMechanism(event, {\n handled: options.error.handled,\n type: 'auto.log.pino',\n });\n\n return event;\n });\n\n const error = captureObj[errorKey];\n if (error) {\n captureException(error, captureContext);\n return;\n }\n\n captureMessage(logMessage, captureContext);\n });\n }\n }\n\n integratedChannel.end.subscribe(data => {\n const {\n instance,\n arguments: args,\n result,\n } = data as { instance: Pino; arguments: PinoHookArgs; result: string };\n onPinoStart(instance, args, JSON.parse(result));\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Integration for Pino logging library.\n * Captures Pino logs as Sentry logs and optionally captures some log levels as events.\n *\n * By default, all Pino loggers will be captured. To ignore a specific logger, use `pinoIntegration.untrackLogger(logger)`.\n *\n * If you disable automatic instrumentation with `autoInstrument: false`, you can mark specific loggers to be tracked with `pinoIntegration.trackLogger(logger)`.\n *\n * Requires Pino >=v8.0.0\n */\nexport const pinoIntegration = Object.assign(_pinoIntegration, {\n trackLogger(logger: unknown): void {\n if (isObjectLike(logger) && 'levels' in logger) {\n (logger as Pino)[SENTRY_TRACK_SYMBOL] = 'track';\n }\n },\n untrackLogger(logger: unknown): void {\n if (isObjectLike(logger) && 'levels' in logger) {\n (logger as Pino)[SENTRY_TRACK_SYMBOL] = 'ignore';\n }\n },\n});\n"],"names":["defineIntegration","_INTERNAL_captureLog","severityLevelFromString","withScope","addExceptionMechanism","captureException","captureMessage","isObjectLike"],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ const processSessionIntegration = core.defineIntegration(() => {
|
|
|
10
10
|
core.startSession();
|
|
11
11
|
process.on("beforeExit", () => {
|
|
12
12
|
const session = core.getIsolationScope().getSession();
|
|
13
|
-
if (session?.status
|
|
13
|
+
if (session?.status === "ok") {
|
|
14
14
|
core.endSession();
|
|
15
15
|
}
|
|
16
16
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"processSession.js","sources":["../../../src/integrations/processSession.ts"],"sourcesContent":["import { defineIntegration, endSession, getIsolationScope, startSession } from '@sentry/core';\n\nconst INTEGRATION_NAME = 'ProcessSession' as const;\n\n/**\n * Records a Session for the current process to track release health.\n */\nexport const processSessionIntegration = defineIntegration(() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n startSession();\n\n // Emitted in the case of healthy sessions, error of `mechanism.handled: true` and unhandledrejections because\n // The 'beforeExit' event is not emitted for conditions causing explicit termination,\n // such as calling process.exit() or uncaught exceptions.\n // Ref: https://nodejs.org/api/process.html#process_event_beforeexit\n process.on('beforeExit', () => {\n const session = getIsolationScope().getSession();\n\n // Only call endSession
|
|
1
|
+
{"version":3,"file":"processSession.js","sources":["../../../src/integrations/processSession.ts"],"sourcesContent":["import { defineIntegration, endSession, getIsolationScope, startSession } from '@sentry/core';\n\nconst INTEGRATION_NAME = 'ProcessSession' as const;\n\n/**\n * Records a Session for the current process to track release health.\n */\nexport const processSessionIntegration = defineIntegration(() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n startSession();\n\n // Emitted in the case of healthy sessions, error of `mechanism.handled: true` and unhandledrejections because\n // The 'beforeExit' event is not emitted for conditions causing explicit termination,\n // such as calling process.exit() or uncaught exceptions.\n // Ref: https://nodejs.org/api/process.html#process_event_beforeexit\n process.on('beforeExit', () => {\n const session = getIsolationScope().getSession();\n\n // Only call endSession if a Session exists on the Scope and has not already reached a\n // Terminal Status, because \"When a session is moved away from ok it must not be updated\n // anymore.\" `ok` is the only non-terminal status.\n // Ref: https://develop.sentry.dev/sdk/sessions/\n if (session?.status === 'ok') {\n endSession();\n }\n });\n },\n };\n});\n"],"names":["defineIntegration","startSession","getIsolationScope","endSession"],"mappings":";;;;AAEA,MAAM,gBAAA,GAAmB,gBAAA;AAKlB,MAAM,yBAAA,GAA4BA,uBAAkB,MAAM;AAC/D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,GAAY;AACV,MAAAC,iBAAA,EAAa;AAMb,MAAA,OAAA,CAAQ,EAAA,CAAG,cAAc,MAAM;AAC7B,QAAA,MAAM,OAAA,GAAUC,sBAAA,EAAkB,CAAE,UAAA,EAAW;AAM/C,QAAA,IAAI,OAAA,EAAS,WAAW,IAAA,EAAM;AAC5B,UAAAC,eAAA,EAAW;AAAA,QACb;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAC;;;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const serverUtils = require('@sentry/server-utils');
|
|
4
|
+
|
|
5
|
+
async function setupHapiErrorHandler(server) {
|
|
6
|
+
serverUtils.attachHapiErrorHandler(server);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
exports.setupHapiErrorHandler = setupHapiErrorHandler;
|
|
10
|
+
//# sourceMappingURL=hapi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hapi.js","sources":["../../../../src/integrations/tracing/hapi.ts"],"sourcesContent":["import { attachHapiErrorHandler } from '@sentry/server-utils';\n\n/**\n * Add a Hapi plugin to capture errors to Sentry.\n *\n * @deprecated The error handler is now registered automatically when the Hapi\n * server starts (via the orchestrion `@hapi/hapi` instrumentation), so calling\n * this is no longer necessary. It remains a safe, idempotent operation when the\n * handler is already attached, and is kept for setups where auto-registration is\n * unavailable. This will be removed in a future major version.\n *\n * @param server The Hapi server to attach the error handler to\n */\nexport async function setupHapiErrorHandler(server: unknown): Promise<void> {\n // oxlint-disable-next-line typescript/no-deprecated\n attachHapiErrorHandler(server as Parameters<typeof attachHapiErrorHandler>[0]);\n}\n"],"names":["attachHapiErrorHandler"],"mappings":";;;;AAaA,eAAsB,sBAAsB,MAAA,EAAgC;AAE1E,EAAAA,kCAAA,CAAuB,MAAsD,CAAA;AAC/E;;;;"}
|
|
@@ -1,42 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
2
|
|
|
3
3
|
const serverUtils = require('@sentry/server-utils');
|
|
4
|
-
const orchestrion = require('@sentry/server-utils/orchestrion');
|
|
5
|
-
const index = require('./fastify/index.js');
|
|
6
|
-
const index$1 = require('./redis/index.js');
|
|
7
4
|
|
|
8
5
|
function getAutoPerformanceIntegrations() {
|
|
9
|
-
return
|
|
10
|
-
orchestrion.expressIntegration(),
|
|
11
|
-
index.fastifyIntegration(),
|
|
12
|
-
orchestrion.graphqlDiagnosticsIntegration(),
|
|
13
|
-
orchestrion.mongodbIntegration(),
|
|
14
|
-
orchestrion.mongooseIntegration(),
|
|
15
|
-
orchestrion.mysqlIntegration(),
|
|
16
|
-
orchestrion.mysql2Integration(),
|
|
17
|
-
// Redis keeps the node wrapper: it wires the cache `responseHook` into the channel subscribers
|
|
18
|
-
// and covers all redis client versions (native diagnostics_channel + orchestrion fallbacks).
|
|
19
|
-
index$1.redisIntegration(),
|
|
20
|
-
orchestrion.postgresIntegration(),
|
|
21
|
-
serverUtils.prismaIntegration(),
|
|
22
|
-
orchestrion.hapiIntegration(),
|
|
23
|
-
orchestrion.koaIntegration(),
|
|
24
|
-
orchestrion.tediousIntegration(),
|
|
25
|
-
orchestrion.genericPoolIntegration(),
|
|
26
|
-
orchestrion.kafkajsIntegration(),
|
|
27
|
-
orchestrion.amqplibIntegration(),
|
|
28
|
-
orchestrion.lruMemoizerIntegration(),
|
|
29
|
-
// AI providers
|
|
30
|
-
// LangChain must come first to disable AI provider integrations before they instrument
|
|
31
|
-
orchestrion.langChainIntegration(),
|
|
32
|
-
orchestrion.langGraphIntegration(),
|
|
33
|
-
orchestrion.vercelAiIntegration(),
|
|
34
|
-
orchestrion.openaiIntegration(),
|
|
35
|
-
orchestrion.anthropicIntegration(),
|
|
36
|
-
orchestrion.googleGenAIIntegration(),
|
|
37
|
-
orchestrion.postgresJsIntegration(),
|
|
38
|
-
orchestrion.firebaseIntegration()
|
|
39
|
-
];
|
|
6
|
+
return serverUtils.getTracingIntegrations();
|
|
40
7
|
}
|
|
41
8
|
|
|
42
9
|
exports.getAutoPerformanceIntegrations = getAutoPerformanceIntegrations;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/integrations/tracing/index.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport {
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/integrations/tracing/index.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport { getTracingIntegrations } from '@sentry/server-utils';\n\nexport function getAutoPerformanceIntegrations(): Integration[] {\n return getTracingIntegrations();\n}\n"],"names":["getTracingIntegrations"],"mappings":";;;;AAGO,SAAS,8BAAA,GAAgD;AAC9D,EAAA,OAAOA,kCAAA,EAAuB;AAChC;;;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const serverUtils = require('@sentry/server-utils');
|
|
4
|
+
|
|
5
|
+
const setupKoaErrorHandler = (app) => {
|
|
6
|
+
serverUtils.attachKoaErrorHandler(app);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
exports.setupKoaErrorHandler = setupKoaErrorHandler;
|
|
10
|
+
//# sourceMappingURL=koa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"koa.js","sources":["../../../../src/integrations/tracing/koa.ts"],"sourcesContent":["import { attachKoaErrorHandler } from '@sentry/server-utils';\n\n/**\n * Add a Koa error handler to capture errors to Sentry.\n *\n * @deprecated The error handler is now registered automatically when the Koa app\n * starts (via the orchestrion `koa` instrumentation), so calling this is no\n * longer necessary. It remains a safe, idempotent operation, and is kept for\n * setups where auto-registration is unavailable. This will be removed in a\n * future major version.\n *\n * @param app The Koa app instance\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n * const Koa = require(\"koa\");\n *\n * const app = new Koa();\n *\n * // Add your routes, etc.\n *\n * app.listen(3000);\n * ```\n */\n\nexport const setupKoaErrorHandler = (app: {\n // oxlint-disable-next-line no-explicit-any\n on: (event: 'error', listener: (...args: any[]) => void) => unknown;\n}): void => {\n // oxlint-disable-next-line typescript/no-deprecated -- internal delegation to the shared implementation\n attachKoaErrorHandler(app);\n};\n"],"names":["attachKoaErrorHandler"],"mappings":";;;;AA0BO,MAAM,oBAAA,GAAuB,CAAC,GAAA,KAGzB;AAEV,EAAAA,iCAAA,CAAsB,GAAG,CAAA;AAC3B;;;;"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const diagnosticsChannel = require('node:diagnostics_channel');
|
|
4
|
+
const core = require('@sentry/core');
|
|
5
|
+
|
|
6
|
+
const INTEGRATION_NAME = "WorkerThreads";
|
|
7
|
+
const workerThreadsIntegration = core.defineIntegration(() => {
|
|
8
|
+
return {
|
|
9
|
+
name: INTEGRATION_NAME,
|
|
10
|
+
setup() {
|
|
11
|
+
diagnosticsChannel.channel("worker_threads").subscribe((event) => {
|
|
12
|
+
if (core.isObjectLike(event) && "worker" in event) {
|
|
13
|
+
captureWorkerThreadEvents(event.worker);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
function captureWorkerThreadEvents(worker) {
|
|
20
|
+
let threadId;
|
|
21
|
+
worker.on("online", () => {
|
|
22
|
+
threadId = worker.threadId;
|
|
23
|
+
}).on("error", (error) => {
|
|
24
|
+
core.captureException(error, {
|
|
25
|
+
mechanism: {
|
|
26
|
+
type: "auto.node.worker_threads",
|
|
27
|
+
handled: false,
|
|
28
|
+
data: threadId !== void 0 ? { threadId: String(threadId) } : void 0
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
exports.workerThreadsIntegration = workerThreadsIntegration;
|
|
35
|
+
//# sourceMappingURL=workerThreads.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workerThreads.js","sources":["../../../src/integrations/workerThreads.ts"],"sourcesContent":["import type { Worker } from 'node:worker_threads';\nimport * as diagnosticsChannel from 'node:diagnostics_channel';\nimport { captureException, defineIntegration, isObjectLike } from '@sentry/core';\n\nconst INTEGRATION_NAME = 'WorkerThreads' as const;\n\n/**\n * Capture events and errors of worker threads.\n * For child process events, use `childProcessIntegration()` instead.\n */\nexport const workerThreadsIntegration = defineIntegration(() => {\n return {\n name: INTEGRATION_NAME,\n setup() {\n diagnosticsChannel.channel('worker_threads').subscribe((event: unknown) => {\n if (isObjectLike(event) && 'worker' in event) {\n captureWorkerThreadEvents(event.worker as Worker);\n }\n });\n },\n };\n});\n\nfunction captureWorkerThreadEvents(worker: Worker): void {\n let threadId: number | undefined;\n\n worker\n .on('online', () => {\n threadId = worker.threadId;\n })\n .on('error', error => {\n captureException(error, {\n mechanism: {\n type: 'auto.node.worker_threads',\n handled: false,\n data: threadId !== undefined ? { threadId: String(threadId) } : undefined,\n },\n });\n });\n}\n"],"names":["defineIntegration","isObjectLike","captureException"],"mappings":";;;;;AAIA,MAAM,gBAAA,GAAmB,eAAA;AAMlB,MAAM,wBAAA,GAA2BA,uBAAkB,MAAM;AAC9D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,KAAA,GAAQ;AACN,MAAA,kBAAA,CAAmB,OAAA,CAAQ,gBAAgB,CAAA,CAAE,SAAA,CAAU,CAAC,KAAA,KAAmB;AACzE,QAAA,IAAIC,iBAAA,CAAa,KAAK,CAAA,IAAK,QAAA,IAAY,KAAA,EAAO;AAC5C,UAAA,yBAAA,CAA0B,MAAM,MAAgB,CAAA;AAAA,QAClD;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAC;AAED,SAAS,0BAA0B,MAAA,EAAsB;AACvD,EAAA,IAAI,QAAA;AAEJ,EAAA,MAAA,CACG,EAAA,CAAG,UAAU,MAAM;AAClB,IAAA,QAAA,GAAW,MAAA,CAAO,QAAA;AAAA,EACpB,CAAC,CAAA,CACA,EAAA,CAAG,OAAA,EAAS,CAAA,KAAA,KAAS;AACpB,IAAAC,qBAAA,CAAiB,KAAA,EAAO;AAAA,MACtB,SAAA,EAAW;AAAA,QACT,IAAA,EAAM,0BAAA;AAAA,QACN,OAAA,EAAS,KAAA;AAAA,QACT,IAAA,EAAM,aAAa,MAAA,GAAY,EAAE,UAAU,MAAA,CAAO,QAAQ,GAAE,GAAI;AAAA;AAClE,KACD,CAAA;AAAA,EACH,CAAC,CAAA;AACL;;;;"}
|
package/build/cjs/sdk/client.js
CHANGED
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const os = require('node:os');
|
|
4
4
|
const api = require('@opentelemetry/api');
|
|
5
5
|
const core = require('@sentry/core');
|
|
6
|
+
const opentelemetry = require('@sentry/opentelemetry');
|
|
7
|
+
const serverUtils = require('@sentry/server-utils');
|
|
6
8
|
const worker_threads = require('worker_threads');
|
|
7
9
|
const debugBuild = require('../debug-build.js');
|
|
8
10
|
|
|
@@ -20,21 +22,29 @@ class NodeClient extends core.ServerRuntimeClient {
|
|
|
20
22
|
core.applySdkMetadata(clientOptions, "node");
|
|
21
23
|
core.debug.log(`Initializing Sentry: process: ${process.pid}, thread: ${worker_threads.isMainThread ? "main" : `worker-${worker_threads.threadId}`}.`);
|
|
22
24
|
super(clientOptions);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
log.attributes
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
process.on("beforeExit", this._logOnExitFlushListener);
|
|
25
|
+
this._logOnExitFlushListener = () => {
|
|
26
|
+
core._INTERNAL_flushLogsBuffer(this);
|
|
27
|
+
};
|
|
28
|
+
if (serverName) {
|
|
29
|
+
this.on("beforeCaptureLog", (log) => {
|
|
30
|
+
log.attributes = {
|
|
31
|
+
...log.attributes,
|
|
32
|
+
"server.address": serverName
|
|
33
|
+
};
|
|
34
|
+
});
|
|
36
35
|
}
|
|
36
|
+
process.on("beforeExit", this._logOnExitFlushListener);
|
|
37
37
|
core._INTERNAL_setDeferSegmentSpanCapture(this);
|
|
38
|
+
opentelemetry.registerPrepareSpanScope(this);
|
|
39
|
+
}
|
|
40
|
+
/** @inheritDoc */
|
|
41
|
+
init() {
|
|
42
|
+
if (this.getOptions().enableOpenTelemetrySetup) {
|
|
43
|
+
this.asyncLocalStorageLookup = opentelemetry.setOpenTelemetryContextAsyncContextStrategy();
|
|
44
|
+
} else {
|
|
45
|
+
this.asyncLocalStorageLookup = { asyncLocalStorage: serverUtils.setAsyncLocalStorageAsyncContextStrategy() };
|
|
46
|
+
}
|
|
47
|
+
super.init();
|
|
38
48
|
}
|
|
39
49
|
/** Get the OTEL tracer. */
|
|
40
50
|
get tracer() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sources":["../../../src/sdk/client.ts"],"sourcesContent":["import * as os from 'node:os';\nimport type { Tracer } from '@opentelemetry/api';\nimport { trace } from '@opentelemetry/api';\nimport type { ServerRuntimeClientOptions } from '@sentry/core';\nimport {\n _INTERNAL_clearAiProviderSkips,\n _INTERNAL_flushLogsBuffer,\n _INTERNAL_setDeferSegmentSpanCapture,\n applySdkMetadata,\n debug,\n SDK_VERSION,\n ServerRuntimeClient,\n} from '@sentry/core';\nimport { type AsyncLocalStorageLookup, type SentryTracerProvider } from '@sentry/opentelemetry';\nimport { isMainThread, threadId } from 'worker_threads';\nimport { DEBUG_BUILD } from '../debug-build';\nimport type { NodeClientOptions } from '../types';\n\nconst DEFAULT_CLIENT_REPORT_FLUSH_INTERVAL_MS = 60_000; // 60s was chosen arbitrarily\n\n/** A client for using Sentry with Node & OpenTelemetry. */\nexport class NodeClient extends ServerRuntimeClient<NodeClientOptions> {\n public traceProvider: SentryTracerProvider | undefined;\n public asyncLocalStorageLookup: AsyncLocalStorageLookup | undefined;\n\n private _tracer: Tracer | undefined;\n private _clientReportInterval: NodeJS.Timeout | undefined;\n private _clientReportOnExitFlushListener: (() => void) | undefined;\n private _logOnExitFlushListener: (() => void) | undefined;\n\n public constructor(options: NodeClientOptions) {\n const serverName =\n options.includeServerName === false\n ? undefined\n : options.serverName || global.process.env.SENTRY_NAME || os.hostname();\n\n const clientOptions: ServerRuntimeClientOptions = {\n ...options,\n platform: 'node',\n // Use provided runtime or default to 'node' with current process version\n runtime: options.runtime || { name: 'node', version: global.process.version },\n serverName,\n };\n\n applySdkMetadata(clientOptions, 'node');\n\n debug.log(`Initializing Sentry: process: ${process.pid}, thread: ${isMainThread ? 'main' : `worker-${threadId}`}.`);\n\n super(clientOptions);\n\n if (this.getOptions().enableLogs) {\n this._logOnExitFlushListener = () => {\n _INTERNAL_flushLogsBuffer(this);\n };\n\n if (serverName) {\n this.on('beforeCaptureLog', log => {\n log.attributes = {\n ...log.attributes,\n 'server.address': serverName,\n };\n });\n }\n\n process.on('beforeExit', this._logOnExitFlushListener);\n }\n\n // Enable deferred segment-span transaction capture here, in the constructor, rather than in\n // `initOtel`. Every client runs its constructor exactly once, whereas `initOtel` only runs on\n // `Sentry.init()` and only fully wires up the first client (a second `init` loses the\n // `setGlobalTracerProvider` race and bails early, and a manually constructed `NodeClient` never\n // runs `initOtel` at all). Anchoring on the constructor means every client — first, second, or\n // manual — defers correctly. It's unconditional and cheap: clients on the OpenTelemetry SDK\n // provider path produce OTel spans that never reach `SentrySpan`, so the strategy is simply never\n // consulted for them.\n _INTERNAL_setDeferSegmentSpanCapture(this);\n }\n\n /** Get the OTEL tracer. */\n public get tracer(): Tracer {\n if (this._tracer) {\n return this._tracer;\n }\n\n const name = '@sentry/node';\n const version = SDK_VERSION;\n const tracer = trace.getTracer(name, version);\n this._tracer = tracer;\n\n return tracer;\n }\n\n /** @inheritDoc */\n // @ts-expect-error - PromiseLike is a subset of Promise\n public async flush(timeout?: number): PromiseLike<boolean> {\n await this.traceProvider?.forceFlush();\n\n if (this.getOptions().sendClientReports) {\n this._flushOutcomes();\n }\n\n return super.flush(timeout);\n }\n\n /** @inheritDoc */\n // @ts-expect-error - PromiseLike is a subset of Promise\n public async close(timeout?: number | undefined): PromiseLike<boolean> {\n if (this._clientReportInterval) {\n clearInterval(this._clientReportInterval);\n }\n\n if (this._clientReportOnExitFlushListener) {\n process.off('beforeExit', this._clientReportOnExitFlushListener);\n }\n\n if (this._logOnExitFlushListener) {\n process.off('beforeExit', this._logOnExitFlushListener);\n }\n\n const allEventsSent = await super.close(timeout);\n if (this.traceProvider) {\n await this.traceProvider.shutdown();\n }\n\n return allEventsSent;\n }\n\n /**\n * Will start tracking client reports for this client.\n *\n * NOTICE: This method will create an interval that is periodically called and attach a `process.on('beforeExit')`\n * hook. To clean up these resources, call `.close()` when you no longer intend to use the client. Not doing so will\n * result in a memory leak.\n */\n // The reason client reports need to be manually activated with this method instead of just enabling them in a\n // constructor, is that if users periodically and unboundedly create new clients, we will create more and more\n // intervals and beforeExit listeners, thus leaking memory. In these situations, users are required to call\n // `client.close()` in order to dispose of the acquired resources.\n // We assume that calling this method in Sentry.init() is a sensible default, because calling Sentry.init() over and\n // over again would also result in memory leaks.\n // Note: We have experimented with using `FinalizationRegisty` to clear the interval when the client is garbage\n // collected, but it did not work, because the cleanup function never got called.\n public startClientReportTracking(): void {\n const clientOptions = this.getOptions();\n if (clientOptions.sendClientReports) {\n this._clientReportOnExitFlushListener = () => {\n this._flushOutcomes();\n };\n\n this._clientReportInterval = setInterval(() => {\n DEBUG_BUILD && debug.log('Flushing client reports based on interval.');\n this._flushOutcomes();\n }, clientOptions.clientReportFlushInterval ?? DEFAULT_CLIENT_REPORT_FLUSH_INTERVAL_MS)\n // Unref is critical for not preventing the process from exiting because the interval is active.\n .unref();\n\n process.on('beforeExit', this._clientReportOnExitFlushListener);\n }\n }\n\n /** @inheritDoc */\n protected _setupIntegrations(): void {\n // Clear AI provider skip registrations before setting up integrations\n // This ensures a clean state between different client initializations\n // (e.g., when LangChain skips OpenAI in one client, but a subsequent client uses OpenAI standalone)\n _INTERNAL_clearAiProviderSkips();\n super._setupIntegrations();\n }\n}\n"],"names":["ServerRuntimeClient","applySdkMetadata","debug","isMainThread","threadId","_INTERNAL_flushLogsBuffer","_INTERNAL_setDeferSegmentSpanCapture","SDK_VERSION","trace","DEBUG_BUILD","_INTERNAL_clearAiProviderSkips"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sources":["../../../src/sdk/client.ts"],"sourcesContent":["import * as os from 'node:os';\nimport type { Tracer } from '@opentelemetry/api';\nimport { trace } from '@opentelemetry/api';\nimport type { ServerRuntimeClientOptions } from '@sentry/core';\nimport {\n _INTERNAL_clearAiProviderSkips,\n _INTERNAL_flushLogsBuffer,\n _INTERNAL_setDeferSegmentSpanCapture,\n applySdkMetadata,\n debug,\n SDK_VERSION,\n ServerRuntimeClient,\n} from '@sentry/core';\nimport {\n type AsyncLocalStorageLookup,\n registerPrepareSpanScope,\n type SentryTracerProvider,\n setOpenTelemetryContextAsyncContextStrategy,\n} from '@sentry/opentelemetry';\nimport { setAsyncLocalStorageAsyncContextStrategy } from '@sentry/server-utils';\nimport { isMainThread, threadId } from 'worker_threads';\nimport { DEBUG_BUILD } from '../debug-build';\nimport type { NodeClientOptions } from '../types';\n\nconst DEFAULT_CLIENT_REPORT_FLUSH_INTERVAL_MS = 60_000; // 60s was chosen arbitrarily\n\n/** A client for using Sentry with Node & OpenTelemetry. */\nexport class NodeClient extends ServerRuntimeClient<NodeClientOptions> {\n public traceProvider: SentryTracerProvider | undefined;\n public asyncLocalStorageLookup: AsyncLocalStorageLookup | undefined;\n\n private _tracer: Tracer | undefined;\n private _clientReportInterval: NodeJS.Timeout | undefined;\n private _clientReportOnExitFlushListener: (() => void) | undefined;\n private _logOnExitFlushListener: (() => void) | undefined;\n\n public constructor(options: NodeClientOptions) {\n const serverName =\n options.includeServerName === false\n ? undefined\n : options.serverName || global.process.env.SENTRY_NAME || os.hostname();\n\n const clientOptions: ServerRuntimeClientOptions = {\n ...options,\n platform: 'node',\n // Use provided runtime or default to 'node' with current process version\n runtime: options.runtime || { name: 'node', version: global.process.version },\n serverName,\n };\n\n applySdkMetadata(clientOptions, 'node');\n\n debug.log(`Initializing Sentry: process: ${process.pid}, thread: ${isMainThread ? 'main' : `worker-${threadId}`}.`);\n\n super(clientOptions);\n\n this._logOnExitFlushListener = () => {\n _INTERNAL_flushLogsBuffer(this);\n };\n\n if (serverName) {\n this.on('beforeCaptureLog', log => {\n log.attributes = {\n ...log.attributes,\n 'server.address': serverName,\n };\n });\n }\n\n process.on('beforeExit', this._logOnExitFlushListener);\n\n // Enable deferred segment-span transaction capture here, in the constructor, rather than in\n // `initOtel`. Every client runs its constructor exactly once, whereas `initOtel` only runs on\n // `Sentry.init()` and only fully wires up the first client (a second `init` loses the\n // `setGlobalTracerProvider` race and bails early, and a manually constructed `NodeClient` never\n // runs `initOtel` at all). Anchoring on the constructor means every client — first, second, or\n // manual — defers correctly. It's unconditional and cheap: clients on the OpenTelemetry SDK\n // provider path produce OTel spans that never reach `SentrySpan`, so the strategy is simply never\n // consulted for them.\n _INTERNAL_setDeferSegmentSpanCapture(this);\n\n // Same constructor anchoring as above: every client must continue incoming (remote) traces,\n // also manually constructed ones that never run `initOtel`.\n registerPrepareSpanScope(this);\n }\n\n /** @inheritDoc */\n public init(): void {\n // Must run before `super.init()`: channel-based integrations capture the strategy's\n // AsyncLocalStorage via `getTracingChannelBinding()` during integration setup.\n if (this.getOptions().enableOpenTelemetrySetup) {\n this.asyncLocalStorageLookup = setOpenTelemetryContextAsyncContextStrategy();\n } else {\n this.asyncLocalStorageLookup = { asyncLocalStorage: setAsyncLocalStorageAsyncContextStrategy() };\n }\n\n super.init();\n }\n\n /** Get the OTEL tracer. */\n public get tracer(): Tracer {\n if (this._tracer) {\n return this._tracer;\n }\n\n const name = '@sentry/node';\n const version = SDK_VERSION;\n const tracer = trace.getTracer(name, version);\n this._tracer = tracer;\n\n return tracer;\n }\n\n /** @inheritDoc */\n // @ts-expect-error - PromiseLike is a subset of Promise\n public async flush(timeout?: number): PromiseLike<boolean> {\n await this.traceProvider?.forceFlush();\n\n if (this.getOptions().sendClientReports) {\n this._flushOutcomes();\n }\n\n return super.flush(timeout);\n }\n\n /** @inheritDoc */\n // @ts-expect-error - PromiseLike is a subset of Promise\n public async close(timeout?: number | undefined): PromiseLike<boolean> {\n if (this._clientReportInterval) {\n clearInterval(this._clientReportInterval);\n }\n\n if (this._clientReportOnExitFlushListener) {\n process.off('beforeExit', this._clientReportOnExitFlushListener);\n }\n\n if (this._logOnExitFlushListener) {\n process.off('beforeExit', this._logOnExitFlushListener);\n }\n\n const allEventsSent = await super.close(timeout);\n if (this.traceProvider) {\n await this.traceProvider.shutdown();\n }\n\n return allEventsSent;\n }\n\n /**\n * Will start tracking client reports for this client.\n *\n * NOTICE: This method will create an interval that is periodically called and attach a `process.on('beforeExit')`\n * hook. To clean up these resources, call `.close()` when you no longer intend to use the client. Not doing so will\n * result in a memory leak.\n */\n // The reason client reports need to be manually activated with this method instead of just enabling them in a\n // constructor, is that if users periodically and unboundedly create new clients, we will create more and more\n // intervals and beforeExit listeners, thus leaking memory. In these situations, users are required to call\n // `client.close()` in order to dispose of the acquired resources.\n // We assume that calling this method in Sentry.init() is a sensible default, because calling Sentry.init() over and\n // over again would also result in memory leaks.\n // Note: We have experimented with using `FinalizationRegisty` to clear the interval when the client is garbage\n // collected, but it did not work, because the cleanup function never got called.\n public startClientReportTracking(): void {\n const clientOptions = this.getOptions();\n if (clientOptions.sendClientReports) {\n this._clientReportOnExitFlushListener = () => {\n this._flushOutcomes();\n };\n\n this._clientReportInterval = setInterval(() => {\n DEBUG_BUILD && debug.log('Flushing client reports based on interval.');\n this._flushOutcomes();\n }, clientOptions.clientReportFlushInterval ?? DEFAULT_CLIENT_REPORT_FLUSH_INTERVAL_MS)\n // Unref is critical for not preventing the process from exiting because the interval is active.\n .unref();\n\n process.on('beforeExit', this._clientReportOnExitFlushListener);\n }\n }\n\n /** @inheritDoc */\n protected _setupIntegrations(): void {\n // Clear AI provider skip registrations before setting up integrations\n // This ensures a clean state between different client initializations\n // (e.g., when LangChain skips OpenAI in one client, but a subsequent client uses OpenAI standalone)\n _INTERNAL_clearAiProviderSkips();\n super._setupIntegrations();\n }\n}\n"],"names":["ServerRuntimeClient","applySdkMetadata","debug","isMainThread","threadId","_INTERNAL_flushLogsBuffer","_INTERNAL_setDeferSegmentSpanCapture","registerPrepareSpanScope","setOpenTelemetryContextAsyncContextStrategy","setAsyncLocalStorageAsyncContextStrategy","SDK_VERSION","trace","DEBUG_BUILD","_INTERNAL_clearAiProviderSkips"],"mappings":"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"}
|