UNPKG

@sentry/node

Version:

Sentry Node SDK using OpenTelemetry for performance instrumentation

164 lines (138 loc) 5.34 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const api = require('@opentelemetry/api'); const instrumentationHttp = require('@opentelemetry/instrumentation-http'); const core = require('@sentry/core'); const nodeCore = require('@sentry/node-core'); const INTEGRATION_NAME = 'Http'; const INSTRUMENTATION_NAME = '@opentelemetry_sentry-patched/instrumentation-http'; const instrumentSentryHttp = nodeCore.generateInstrumentOnce( `${INTEGRATION_NAME}.sentry`, options => { return new nodeCore.SentryHttpInstrumentation(options); }, ); const instrumentOtelHttp = nodeCore.generateInstrumentOnce(INTEGRATION_NAME, config => { const instrumentation = new instrumentationHttp.HttpInstrumentation({ ...config, // This is hard-coded and can never be overridden by the user disableIncomingRequestInstrumentation: true, }); // We want to update the logger namespace so we can better identify what is happening here try { instrumentation['_diag'] = api.diag.createComponentLogger({ namespace: INSTRUMENTATION_NAME, }); // @ts-expect-error We are writing a read-only property here... instrumentation.instrumentationName = INSTRUMENTATION_NAME; } catch { // ignore errors here... } return instrumentation; }); /** Exported only for tests. */ function _shouldUseOtelHttpInstrumentation( options, clientOptions = {}, ) { // If `spans` is passed in, it takes precedence // Else, we by default emit spans, unless `skipOpenTelemetrySetup` is set to `true` or spans are not enabled if (typeof options.spans === 'boolean') { return options.spans; } if (clientOptions.skipOpenTelemetrySetup) { return false; } // IMPORTANT: We only disable span instrumentation when spans are not enabled _and_ we are on Node 22+, // as otherwise the necessary diagnostics channel is not available yet if (!core.hasSpansEnabled(clientOptions) && nodeCore.NODE_VERSION.major >= 22) { return false; } return true; } /** * The http integration instruments Node's internal http and https modules. * It creates breadcrumbs and spans for outgoing HTTP requests which will be attached to the currently active span. */ const httpIntegration = core.defineIntegration((options = {}) => { const dropSpansForIncomingRequestStatusCodes = options.dropSpansForIncomingRequestStatusCodes ?? [ [401, 404], [300, 399], ]; return { name: INTEGRATION_NAME, setupOnce() { const clientOptions = (core.getClient()?.getOptions() || {}) ; const useOtelHttpInstrumentation = _shouldUseOtelHttpInstrumentation(options, clientOptions); const disableIncomingRequestSpans = options.disableIncomingRequestSpans ?? !core.hasSpansEnabled(clientOptions); // This is Sentry-specific instrumentation for request isolation and breadcrumbs instrumentSentryHttp({ ...options, disableIncomingRequestSpans, ignoreSpansForIncomingRequests: options.ignoreIncomingRequests, // If spans are not instrumented, it means the HttpInstrumentation has not been added // In that case, we want to handle trace propagation ourselves propagateTraceInOutgoingRequests: !useOtelHttpInstrumentation, }); // This is the "regular" OTEL instrumentation that emits spans if (useOtelHttpInstrumentation) { const instrumentationConfig = getConfigWithDefaults(options); instrumentOtelHttp(instrumentationConfig); } }, processEvent(event) { // Drop transaction if it has a status code that should be ignored if (event.type === 'transaction') { const statusCode = event.contexts?.trace?.data?.['http.response.status_code']; if ( typeof statusCode === 'number' && dropSpansForIncomingRequestStatusCodes.some(code => { if (typeof code === 'number') { return code === statusCode; } const [min, max] = code; return statusCode >= min && statusCode <= max; }) ) { return null; } } return event; }, }; }); function getConfigWithDefaults(options = {}) { const instrumentationConfig = { ignoreOutgoingRequestHook: request => { const url = nodeCore.getRequestUrl(request); if (!url) { return false; } const _ignoreOutgoingRequests = options.ignoreOutgoingRequests; if (_ignoreOutgoingRequests?.(url, request)) { return true; } return false; }, requireParentforOutgoingSpans: false, requestHook: (span, req) => { nodeCore.addOriginToSpan(span, 'auto.http.otel.http'); options.instrumentation?.requestHook?.(span, req); }, responseHook: (span, res) => { options.instrumentation?.responseHook?.(span, res); }, applyCustomAttributesOnSpan: ( span, request, response, ) => { options.instrumentation?.applyCustomAttributesOnSpan?.(span, request, response); }, } ; return instrumentationConfig; } exports._shouldUseOtelHttpInstrumentation = _shouldUseOtelHttpInstrumentation; exports.httpIntegration = httpIntegration; exports.instrumentOtelHttp = instrumentOtelHttp; exports.instrumentSentryHttp = instrumentSentryHttp; //# sourceMappingURL=http.js.map