192 lines
5.9 KiB
JavaScript
192 lines
5.9 KiB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
const core = require('@sentry/core');
|
|
const utils = require('@sentry/utils');
|
|
|
|
/**
|
|
* Create and track fetch request spans for usage in combination with `addInstrumentationHandler`.
|
|
*
|
|
* @returns Span if a span was created, otherwise void.
|
|
*/
|
|
function instrumentFetchRequest(
|
|
handlerData,
|
|
shouldCreateSpan,
|
|
shouldAttachHeaders,
|
|
spans,
|
|
spanOrigin = 'auto.http.browser',
|
|
) {
|
|
if (!core.hasTracingEnabled() || !handlerData.fetchData) {
|
|
return undefined;
|
|
}
|
|
|
|
const shouldCreateSpanResult = shouldCreateSpan(handlerData.fetchData.url);
|
|
|
|
if (handlerData.endTimestamp && shouldCreateSpanResult) {
|
|
const spanId = handlerData.fetchData.__span;
|
|
if (!spanId) return;
|
|
|
|
const span = spans[spanId];
|
|
if (span) {
|
|
endSpan(span, handlerData);
|
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
delete spans[spanId];
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
const scope = core.getCurrentScope();
|
|
const client = core.getClient();
|
|
|
|
const { method, url } = handlerData.fetchData;
|
|
|
|
const fullUrl = getFullURL(url);
|
|
const host = fullUrl ? utils.parseUrl(fullUrl).host : undefined;
|
|
|
|
const span = shouldCreateSpanResult
|
|
? core.startInactiveSpan({
|
|
name: `${method} ${url}`,
|
|
onlyIfParent: true,
|
|
attributes: {
|
|
url,
|
|
type: 'fetch',
|
|
'http.method': method,
|
|
'http.url': fullUrl,
|
|
'server.address': host,
|
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanOrigin,
|
|
},
|
|
op: 'http.client',
|
|
})
|
|
: undefined;
|
|
|
|
if (span) {
|
|
handlerData.fetchData.__span = span.spanContext().spanId;
|
|
spans[span.spanContext().spanId] = span;
|
|
}
|
|
|
|
if (shouldAttachHeaders(handlerData.fetchData.url) && client) {
|
|
const request = handlerData.args[0];
|
|
|
|
// In case the user hasn't set the second argument of a fetch call we default it to `{}`.
|
|
handlerData.args[1] = handlerData.args[1] || {};
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const options = handlerData.args[1];
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
|
|
options.headers = addTracingHeadersToFetchRequest(request, client, scope, options, span);
|
|
}
|
|
|
|
return span;
|
|
}
|
|
|
|
/**
|
|
* Adds sentry-trace and baggage headers to the various forms of fetch headers
|
|
*/
|
|
function addTracingHeadersToFetchRequest(
|
|
request, // unknown is actually type Request but we can't export DOM types from this package,
|
|
client,
|
|
scope,
|
|
options
|
|
|
|
,
|
|
requestSpan,
|
|
) {
|
|
// eslint-disable-next-line deprecation/deprecation
|
|
const span = requestSpan || scope.getSpan();
|
|
|
|
const isolationScope = core.getIsolationScope();
|
|
|
|
const { traceId, spanId, sampled, dsc } = {
|
|
...isolationScope.getPropagationContext(),
|
|
...scope.getPropagationContext(),
|
|
};
|
|
|
|
const sentryTraceHeader = span ? core.spanToTraceHeader(span) : utils.generateSentryTraceHeader(traceId, spanId, sampled);
|
|
|
|
const sentryBaggageHeader = utils.dynamicSamplingContextToSentryBaggageHeader(
|
|
dsc ||
|
|
(span ? core.getDynamicSamplingContextFromSpan(span) : core.getDynamicSamplingContextFromClient(traceId, client, scope)),
|
|
);
|
|
|
|
const headers =
|
|
options.headers ||
|
|
(typeof Request !== 'undefined' && utils.isInstanceOf(request, Request) ? (request ).headers : undefined);
|
|
|
|
if (!headers) {
|
|
return { 'sentry-trace': sentryTraceHeader, baggage: sentryBaggageHeader };
|
|
} else if (typeof Headers !== 'undefined' && utils.isInstanceOf(headers, Headers)) {
|
|
const newHeaders = new Headers(headers );
|
|
|
|
newHeaders.append('sentry-trace', sentryTraceHeader);
|
|
|
|
if (sentryBaggageHeader) {
|
|
// If the same header is appended multiple times the browser will merge the values into a single request header.
|
|
// Its therefore safe to simply push a "baggage" entry, even though there might already be another baggage header.
|
|
newHeaders.append(utils.BAGGAGE_HEADER_NAME, sentryBaggageHeader);
|
|
}
|
|
|
|
return newHeaders ;
|
|
} else if (Array.isArray(headers)) {
|
|
const newHeaders = [...headers, ['sentry-trace', sentryTraceHeader]];
|
|
|
|
if (sentryBaggageHeader) {
|
|
// If there are multiple entries with the same key, the browser will merge the values into a single request header.
|
|
// Its therefore safe to simply push a "baggage" entry, even though there might already be another baggage header.
|
|
newHeaders.push([utils.BAGGAGE_HEADER_NAME, sentryBaggageHeader]);
|
|
}
|
|
|
|
return newHeaders ;
|
|
} else {
|
|
const existingBaggageHeader = 'baggage' in headers ? headers.baggage : undefined;
|
|
const newBaggageHeaders = [];
|
|
|
|
if (Array.isArray(existingBaggageHeader)) {
|
|
newBaggageHeaders.push(...existingBaggageHeader);
|
|
} else if (existingBaggageHeader) {
|
|
newBaggageHeaders.push(existingBaggageHeader);
|
|
}
|
|
|
|
if (sentryBaggageHeader) {
|
|
newBaggageHeaders.push(sentryBaggageHeader);
|
|
}
|
|
|
|
return {
|
|
...(headers ),
|
|
'sentry-trace': sentryTraceHeader,
|
|
baggage: newBaggageHeaders.length > 0 ? newBaggageHeaders.join(',') : undefined,
|
|
};
|
|
}
|
|
}
|
|
|
|
function getFullURL(url) {
|
|
try {
|
|
const parsed = new URL(url);
|
|
return parsed.href;
|
|
} catch (e) {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
function endSpan(span, handlerData) {
|
|
if (handlerData.response) {
|
|
core.setHttpStatus(span, handlerData.response.status);
|
|
|
|
const contentLength =
|
|
handlerData.response && handlerData.response.headers && handlerData.response.headers.get('content-length');
|
|
|
|
if (contentLength) {
|
|
const contentLengthNum = parseInt(contentLength);
|
|
if (contentLengthNum > 0) {
|
|
span.setAttribute('http.response_content_length', contentLengthNum);
|
|
}
|
|
}
|
|
} else if (handlerData.error) {
|
|
span.setStatus('internal_error');
|
|
}
|
|
span.end();
|
|
}
|
|
|
|
exports.addTracingHeadersToFetchRequest = addTracingHeadersToFetchRequest;
|
|
exports.instrumentFetchRequest = instrumentFetchRequest;
|
|
//# sourceMappingURL=fetch.js.map
|