@sentry/node
Version:
Official Sentry SDK for Node.js
211 lines (176 loc) • 6.05 kB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true });
const utils = require('@sentry/utils');
const http = require('../utils/http.js');
const NODE_VERSION = utils.parseSemver(process.versions.node);
exports.ChannelName = void 0; (function (ChannelName) {
// https://github.com/nodejs/undici/blob/e6fc80f809d1217814c044f52ed40ef13f21e43c/docs/api/DiagnosticsChannel.md#undicirequestcreate
const RequestCreate = 'undici:request:create'; ChannelName["RequestCreate"] = RequestCreate;
const RequestEnd = 'undici:request:headers'; ChannelName["RequestEnd"] = RequestEnd;
const RequestError = 'undici:request:error'; ChannelName["RequestError"] = RequestError;
})(exports.ChannelName || (exports.ChannelName = {}));
// Please note that you cannot use `console.log` to debug the callbacks registered to the `diagnostics_channel` API.
// To debug, you can use `writeFileSync` to write to a file:
// https://nodejs.org/api/async_hooks.html#printing-in-asynchook-callbacks
/**
* Instruments outgoing HTTP requests made with the `undici` package via
* Node's `diagnostics_channel` API.
*
* Supports Undici 4.7.0 or higher.
*
* Requires Node 16.17.0 or higher.
*/
class Undici {
/**
* @inheritDoc
*/
static __initStatic() {this.id = 'Undici';}
/**
* @inheritDoc
*/
__init() {this.name = Undici.id;}
constructor(_options = {}) {Undici.prototype.__init.call(this);
this._options = {
breadcrumbs: _options.breadcrumbs === undefined ? true : _options.breadcrumbs,
shouldCreateSpanForRequest: _options.shouldCreateSpanForRequest || (() => true),
};
}
/**
* @inheritDoc
*/
setupOnce(_addGlobalEventProcessor, getCurrentHub) {
// Requires Node 16+ to use the diagnostics_channel API.
if (NODE_VERSION.major && NODE_VERSION.major < 16) {
return;
}
let ds;
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
ds = utils.dynamicRequire(module, 'diagnostics_channel') ;
} catch (e) {
// no-op
}
if (!ds || !ds.subscribe) {
return;
}
// https://github.com/nodejs/undici/blob/e6fc80f809d1217814c044f52ed40ef13f21e43c/docs/api/DiagnosticsChannel.md
ds.subscribe(exports.ChannelName.RequestCreate, message => {
const hub = getCurrentHub();
if (!hub.getIntegration(Undici)) {
return;
}
const { request } = message ;
const url = new URL(request.path, request.origin);
const stringUrl = url.toString();
if (http.isSentryRequest(stringUrl) || request.__sentry__ !== undefined) {
return;
}
const client = hub.getClient();
const scope = hub.getScope();
const activeSpan = scope.getSpan();
if (activeSpan && client) {
const clientOptions = client.getOptions();
const shouldCreateSpan = this._options.shouldCreateSpanForRequest(stringUrl);
if (shouldCreateSpan) {
const data = {};
const params = url.searchParams.toString();
if (params) {
data['http.query'] = `?${params}`;
}
if (url.hash) {
data['http.fragment'] = url.hash;
}
const span = activeSpan.startChild({
op: 'http.client',
description: `${request.method || 'GET'} ${utils.stripUrlQueryAndFragment(stringUrl)}`,
data,
});
request.__sentry__ = span;
const shouldPropagate = clientOptions.tracePropagationTargets
? utils.stringMatchesSomePattern(stringUrl, clientOptions.tracePropagationTargets)
: true;
if (shouldPropagate) {
request.addHeader('sentry-trace', span.toTraceparent());
if (span.transaction) {
const dynamicSamplingContext = span.transaction.getDynamicSamplingContext();
const sentryBaggageHeader = utils.dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
if (sentryBaggageHeader) {
request.addHeader('baggage', sentryBaggageHeader);
}
}
}
}
}
});
ds.subscribe(exports.ChannelName.RequestEnd, message => {
const hub = getCurrentHub();
if (!hub.getIntegration(Undici)) {
return;
}
const { request, response } = message ;
const url = new URL(request.path, request.origin);
const stringUrl = url.toString();
if (http.isSentryRequest(stringUrl)) {
return;
}
const span = request.__sentry__;
if (span) {
span.setHttpStatus(response.statusCode);
span.finish();
}
if (this._options.breadcrumbs) {
hub.addBreadcrumb(
{
category: 'http',
data: {
method: request.method,
status_code: response.statusCode,
url: stringUrl,
},
type: 'http',
},
{
event: 'response',
request,
response,
},
);
}
});
ds.subscribe(exports.ChannelName.RequestError, message => {
const hub = getCurrentHub();
if (!hub.getIntegration(Undici)) {
return;
}
const { request } = message ;
const url = new URL(request.path, request.origin);
const stringUrl = url.toString();
if (http.isSentryRequest(stringUrl)) {
return;
}
const span = request.__sentry__;
if (span) {
span.setStatus('internal_error');
span.finish();
}
if (this._options.breadcrumbs) {
hub.addBreadcrumb(
{
category: 'http',
data: {
method: request.method,
url: stringUrl,
},
level: 'error',
type: 'http',
},
{
event: 'error',
request,
},
);
}
});
}
} Undici.__initStatic();
exports.Undici = Undici;
//# sourceMappingURL=index.js.map