mirror of
https://github.com/rxliuli/apps.apple.com.git
synced 2025-11-10 00:30:32 +00:00
init commit
This commit is contained in:
335
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/request.js
generated
vendored
Normal file
335
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/request.js
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
import { _optionalChain } from '@sentry/utils/esm/buildPolyfills';
|
||||
import { hasTracingEnabled, getCurrentHub } from '@sentry/core';
|
||||
import { addInstrumentationHandler, browserPerformanceTimeOrigin, dynamicSamplingContextToSentryBaggageHeader, isInstanceOf, BAGGAGE_HEADER_NAME, SENTRY_XHR_DATA_KEY, stringMatchesSomePattern } from '@sentry/utils';
|
||||
|
||||
/* eslint-disable max-lines */
|
||||
|
||||
const DEFAULT_TRACE_PROPAGATION_TARGETS = ['localhost', /^\/(?!\/)/];
|
||||
|
||||
/** Options for Request Instrumentation */
|
||||
|
||||
const defaultRequestInstrumentationOptions = {
|
||||
traceFetch: true,
|
||||
traceXHR: true,
|
||||
// TODO (v8): Remove this property
|
||||
tracingOrigins: DEFAULT_TRACE_PROPAGATION_TARGETS,
|
||||
tracePropagationTargets: DEFAULT_TRACE_PROPAGATION_TARGETS,
|
||||
_experiments: {},
|
||||
};
|
||||
|
||||
/** Registers span creators for xhr and fetch requests */
|
||||
function instrumentOutgoingRequests(_options) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const { traceFetch, traceXHR, tracePropagationTargets, tracingOrigins, shouldCreateSpanForRequest, _experiments } = {
|
||||
traceFetch: defaultRequestInstrumentationOptions.traceFetch,
|
||||
traceXHR: defaultRequestInstrumentationOptions.traceXHR,
|
||||
..._options,
|
||||
};
|
||||
|
||||
const shouldCreateSpan =
|
||||
typeof shouldCreateSpanForRequest === 'function' ? shouldCreateSpanForRequest : (_) => true;
|
||||
|
||||
// TODO(v8) Remove tracingOrigins here
|
||||
// The only reason we're passing it in here is because this instrumentOutgoingRequests function is publicly exported
|
||||
// and we don't want to break the API. We can remove it in v8.
|
||||
const shouldAttachHeadersWithTargets = (url) =>
|
||||
shouldAttachHeaders(url, tracePropagationTargets || tracingOrigins);
|
||||
|
||||
const spans = {};
|
||||
|
||||
if (traceFetch) {
|
||||
addInstrumentationHandler('fetch', (handlerData) => {
|
||||
const createdSpan = fetchCallback(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans);
|
||||
if (_optionalChain([_experiments, 'optionalAccess', _2 => _2.enableHTTPTimings]) && createdSpan) {
|
||||
addHTTPTimings(createdSpan);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (traceXHR) {
|
||||
addInstrumentationHandler('xhr', (handlerData) => {
|
||||
const createdSpan = xhrCallback(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans);
|
||||
if (_optionalChain([_experiments, 'optionalAccess', _3 => _3.enableHTTPTimings]) && createdSpan) {
|
||||
addHTTPTimings(createdSpan);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary observer to listen to the next fetch/xhr resourcing timings,
|
||||
* so that when timings hit their per-browser limit they don't need to be removed.
|
||||
*
|
||||
* @param span A span that has yet to be finished, must contain `url` on data.
|
||||
*/
|
||||
function addHTTPTimings(span) {
|
||||
const url = span.data.url;
|
||||
const observer = new PerformanceObserver(list => {
|
||||
const entries = list.getEntries() ;
|
||||
entries.forEach(entry => {
|
||||
if ((entry.initiatorType === 'fetch' || entry.initiatorType === 'xmlhttprequest') && entry.name.endsWith(url)) {
|
||||
const spanData = resourceTimingEntryToSpanData(entry);
|
||||
spanData.forEach(data => span.setData(...data));
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe({
|
||||
entryTypes: ['resource'],
|
||||
});
|
||||
}
|
||||
|
||||
function resourceTimingEntryToSpanData(resourceTiming) {
|
||||
const version = resourceTiming.nextHopProtocol.split('/')[1] || 'none';
|
||||
|
||||
const timingSpanData = [];
|
||||
if (version) {
|
||||
timingSpanData.push(['network.protocol.version', version]);
|
||||
}
|
||||
|
||||
if (!browserPerformanceTimeOrigin) {
|
||||
return timingSpanData;
|
||||
}
|
||||
return [
|
||||
...timingSpanData,
|
||||
['http.request.connect_start', (browserPerformanceTimeOrigin + resourceTiming.connectStart) / 1000],
|
||||
['http.request.request_start', (browserPerformanceTimeOrigin + resourceTiming.requestStart) / 1000],
|
||||
['http.request.response_start', (browserPerformanceTimeOrigin + resourceTiming.responseStart) / 1000],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that determines whether to attach tracing headers to a request.
|
||||
* This was extracted from `instrumentOutgoingRequests` to make it easier to test shouldAttachHeaders.
|
||||
* We only export this fuction for testing purposes.
|
||||
*/
|
||||
function shouldAttachHeaders(url, tracePropagationTargets) {
|
||||
return stringMatchesSomePattern(url, tracePropagationTargets || DEFAULT_TRACE_PROPAGATION_TARGETS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and track fetch request spans
|
||||
*
|
||||
* @returns Span if a span was created, otherwise void.
|
||||
*/
|
||||
function fetchCallback(
|
||||
handlerData,
|
||||
shouldCreateSpan,
|
||||
shouldAttachHeaders,
|
||||
spans,
|
||||
) {
|
||||
if (!hasTracingEnabled() || !(handlerData.fetchData && shouldCreateSpan(handlerData.fetchData.url))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handlerData.endTimestamp) {
|
||||
const spanId = handlerData.fetchData.__span;
|
||||
if (!spanId) return;
|
||||
|
||||
const span = spans[spanId];
|
||||
if (span) {
|
||||
if (handlerData.response) {
|
||||
// TODO (kmclb) remove this once types PR goes through
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
span.setHttpStatus(handlerData.response.status);
|
||||
|
||||
const contentLength =
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
handlerData.response && handlerData.response.headers && handlerData.response.headers.get('content-length');
|
||||
|
||||
const contentLengthNum = parseInt(contentLength);
|
||||
if (contentLengthNum > 0) {
|
||||
span.setData('http.response_content_length', contentLengthNum);
|
||||
}
|
||||
} else if (handlerData.error) {
|
||||
span.setStatus('internal_error');
|
||||
}
|
||||
span.finish();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete spans[spanId];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const currentSpan = getCurrentHub().getScope().getSpan();
|
||||
const activeTransaction = currentSpan && currentSpan.transaction;
|
||||
|
||||
if (currentSpan && activeTransaction) {
|
||||
const { method, url } = handlerData.fetchData;
|
||||
const span = currentSpan.startChild({
|
||||
data: {
|
||||
url,
|
||||
type: 'fetch',
|
||||
'http.method': method,
|
||||
},
|
||||
description: `${method} ${url}`,
|
||||
op: 'http.client',
|
||||
});
|
||||
|
||||
handlerData.fetchData.__span = span.spanId;
|
||||
spans[span.spanId] = span;
|
||||
|
||||
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];
|
||||
|
||||
if (shouldAttachHeaders(handlerData.fetchData.url)) {
|
||||
options.headers = addTracingHeadersToFetchRequest(
|
||||
request,
|
||||
activeTransaction.getDynamicSamplingContext(),
|
||||
span,
|
||||
options,
|
||||
);
|
||||
}
|
||||
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,
|
||||
dynamicSamplingContext,
|
||||
span,
|
||||
options
|
||||
|
||||
,
|
||||
) {
|
||||
const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
|
||||
const sentryTraceHeader = span.toTraceparent();
|
||||
|
||||
const headers =
|
||||
typeof Request !== 'undefined' && isInstanceOf(request, Request) ? (request ).headers : options.headers;
|
||||
|
||||
if (!headers) {
|
||||
return { 'sentry-trace': sentryTraceHeader, baggage: sentryBaggageHeader };
|
||||
} else if (typeof Headers !== 'undefined' && 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(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([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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and track xhr request spans
|
||||
*
|
||||
* @returns Span if a span was created, otherwise void.
|
||||
*/
|
||||
function xhrCallback(
|
||||
handlerData,
|
||||
shouldCreateSpan,
|
||||
shouldAttachHeaders,
|
||||
spans,
|
||||
) {
|
||||
const xhr = handlerData.xhr;
|
||||
const sentryXhrData = xhr && xhr[SENTRY_XHR_DATA_KEY];
|
||||
|
||||
if (
|
||||
!hasTracingEnabled() ||
|
||||
(xhr && xhr.__sentry_own_request__) ||
|
||||
!(xhr && sentryXhrData && shouldCreateSpan(sentryXhrData.url))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check first if the request has finished and is tracked by an existing span which should now end
|
||||
if (handlerData.endTimestamp) {
|
||||
const spanId = xhr.__sentry_xhr_span_id__;
|
||||
if (!spanId) return;
|
||||
|
||||
const span = spans[spanId];
|
||||
if (span) {
|
||||
span.setHttpStatus(sentryXhrData.status_code);
|
||||
span.finish();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete spans[spanId];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const currentSpan = getCurrentHub().getScope().getSpan();
|
||||
const activeTransaction = currentSpan && currentSpan.transaction;
|
||||
|
||||
if (currentSpan && activeTransaction) {
|
||||
const span = currentSpan.startChild({
|
||||
data: {
|
||||
...sentryXhrData.data,
|
||||
type: 'xhr',
|
||||
'http.method': sentryXhrData.method,
|
||||
url: sentryXhrData.url,
|
||||
},
|
||||
description: `${sentryXhrData.method} ${sentryXhrData.url}`,
|
||||
op: 'http.client',
|
||||
});
|
||||
|
||||
xhr.__sentry_xhr_span_id__ = span.spanId;
|
||||
spans[xhr.__sentry_xhr_span_id__] = span;
|
||||
|
||||
if (xhr.setRequestHeader && shouldAttachHeaders(sentryXhrData.url)) {
|
||||
try {
|
||||
xhr.setRequestHeader('sentry-trace', span.toTraceparent());
|
||||
|
||||
const dynamicSamplingContext = activeTransaction.getDynamicSamplingContext();
|
||||
const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
|
||||
|
||||
if (sentryBaggageHeader) {
|
||||
// From MDN: "If this method is called several times with the same header, the values are merged into one single request header."
|
||||
// We can therefore simply set a baggage header without checking what was there before
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader
|
||||
xhr.setRequestHeader(BAGGAGE_HEADER_NAME, sentryBaggageHeader);
|
||||
}
|
||||
} catch (_) {
|
||||
// Error: InvalidStateError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED.
|
||||
}
|
||||
}
|
||||
|
||||
return span;
|
||||
}
|
||||
}
|
||||
|
||||
export { DEFAULT_TRACE_PROPAGATION_TARGETS, addTracingHeadersToFetchRequest, defaultRequestInstrumentationOptions, instrumentOutgoingRequests, shouldAttachHeaders };
|
||||
//# sourceMappingURL=request.js.map
|
||||
Reference in New Issue
Block a user