var { _optionalChain } = require('@sentry/utils'); Object.defineProperty(exports, '__esModule', { value: true }); const api = require('@opentelemetry/api'); const instrumentationUndici = require('@opentelemetry/instrumentation-undici'); const core = require('@sentry/core'); const opentelemetry = require('@sentry/opentelemetry'); const utils = require('@sentry/utils'); const _nativeNodeFetchIntegration = ((options = {}) => { const _breadcrumbs = typeof options.breadcrumbs === 'undefined' ? true : options.breadcrumbs; const _ignoreOutgoingRequests = options.ignoreOutgoingRequests; return { name: 'NodeFetch', setupOnce() { const instrumentation = new instrumentationUndici.UndiciInstrumentation({ requireParentforSpans: false, ignoreRequestHook: request => { const url = getAbsoluteUrl(request.origin, request.path); const shouldIgnore = _ignoreOutgoingRequests && url && _ignoreOutgoingRequests(url); if (shouldIgnore) { return true; } // If tracing is disabled, we still want to propagate traces // So we do that manually here, matching what the instrumentation does otherwise if (!core.hasTracingEnabled()) { const ctx = api.context.active(); const addedHeaders = {}; // We generate a virtual span context from the active one, // Where we attach the URL to the trace state, so the propagator can pick it up const activeSpan = api.trace.getSpan(ctx); const propagationContext = activeSpan ? opentelemetry.getPropagationContextFromSpan(activeSpan) : core.getCurrentScope().getPropagationContext(); const spanContext = opentelemetry.generateSpanContextForPropagationContext(propagationContext); // We know that in practice we'll _always_ haven a traceState here spanContext.traceState = _optionalChain([spanContext, 'access', _2 => _2.traceState, 'optionalAccess', _3 => _3.set, 'call', _4 => _4('sentry.url', url)]); const ctxWithUrlTraceState = api.trace.setSpanContext(ctx, spanContext); api.propagation.inject(ctxWithUrlTraceState, addedHeaders); const requestHeaders = request.headers; if (Array.isArray(requestHeaders)) { Object.entries(addedHeaders).forEach(headers => requestHeaders.push(...headers)); } else { request.headers += Object.entries(addedHeaders) .map(([k, v]) => `${k}: ${v}\r\n`) .join(''); } // Prevent starting a span for this request return true; } return false; }, startSpanHook: () => { return { [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.node_fetch', }; }, responseHook: (_, { request, response }) => { if (_breadcrumbs) { addRequestBreadcrumb(request, response); } }, }); opentelemetry.addOpenTelemetryInstrumentation(instrumentation); }, }; }) ; const nativeNodeFetchIntegration = core.defineIntegration(_nativeNodeFetchIntegration); /** Add a breadcrumb for outgoing requests. */ function addRequestBreadcrumb(request, response) { const data = getBreadcrumbData(request); const statusCode = response.statusCode; const level = utils.getBreadcrumbLogLevelFromHttpStatusCode(statusCode); core.addBreadcrumb( { category: 'http', data: { status_code: statusCode, ...data, }, type: 'http', level, }, { event: 'response', request, response, }, ); } function getBreadcrumbData(request) { try { const url = new URL(request.path, request.origin); const parsedUrl = utils.parseUrl(url.toString()); const data = { url: utils.getSanitizedUrlString(parsedUrl), 'http.method': request.method || 'GET', }; if (parsedUrl.search) { data['http.query'] = parsedUrl.search; } if (parsedUrl.hash) { data['http.fragment'] = parsedUrl.hash; } return data; } catch (e) { return {}; } } // Matching the behavior of the base instrumentation function getAbsoluteUrl(origin, path = '/') { const url = `${origin}`; if (url.endsWith('/') && path.startsWith('/')) { return `${url}${path.slice(1)}`; } if (!url.endsWith('/') && !path.startsWith('/')) { return `${url}/${path.slice(1)}`; } return `${url}${path}`; } exports.nativeNodeFetchIntegration = nativeNodeFetchIntegration; //# sourceMappingURL=node-fetch.js.map