summaryrefslogtreecommitdiff
path: root/shared/logger/node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js
diff options
context:
space:
mode:
Diffstat (limited to 'shared/logger/node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js')
-rw-r--r--shared/logger/node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js300
1 files changed, 300 insertions, 0 deletions
diff --git a/shared/logger/node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js b/shared/logger/node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js
new file mode 100644
index 0000000..3b79fb3
--- /dev/null
+++ b/shared/logger/node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js
@@ -0,0 +1,300 @@
+import { TRACING_DEFAULTS, addTracingExtensions, extractTraceparentData, startIdleTransaction, getActiveTransaction } from '@sentry/core';
+import { logger, baggageHeaderToDynamicSamplingContext, getDomElement } from '@sentry/utils';
+import { registerBackgroundTabDetection } from './backgroundtab.js';
+import { startTrackingWebVitals, startTrackingLongTasks, startTrackingInteractions, addPerformanceEntries } from './metrics/index.js';
+import { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './request.js';
+import { instrumentRoutingWithDefaults } from './router.js';
+import { WINDOW } from './types.js';
+
+const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing';
+
+/** Options for Browser Tracing integration */
+
+const DEFAULT_BROWSER_TRACING_OPTIONS = {
+ ...TRACING_DEFAULTS,
+ markBackgroundTransactions: true,
+ routingInstrumentation: instrumentRoutingWithDefaults,
+ startTransactionOnLocationChange: true,
+ startTransactionOnPageLoad: true,
+ enableLongTask: true,
+ ...defaultRequestInstrumentationOptions,
+};
+
+/**
+ * The Browser Tracing integration automatically instruments browser pageload/navigation
+ * actions as transactions, and captures requests, metrics and errors as spans.
+ *
+ * The integration can be configured with a variety of options, and can be extended to use
+ * any routing library. This integration uses {@see IdleTransaction} to create transactions.
+ */
+class BrowserTracing {
+ // This class currently doesn't have a static `id` field like the other integration classes, because it prevented
+ // @sentry/tracing from being treeshaken. Tree shakers do not like static fields, because they behave like side effects.
+ // TODO: Come up with a better plan, than using static fields on integration classes, and use that plan on all
+ // integrations.
+
+ /** Browser Tracing integration options */
+
+ /**
+ * @inheritDoc
+ */
+ __init() {this.name = BROWSER_TRACING_INTEGRATION_ID;}
+
+ __init2() {this._hasSetTracePropagationTargets = false;}
+
+ constructor(_options) {BrowserTracing.prototype.__init.call(this);BrowserTracing.prototype.__init2.call(this);
+ addTracingExtensions();
+
+ if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
+ this._hasSetTracePropagationTargets = !!(
+ _options &&
+ // eslint-disable-next-line deprecation/deprecation
+ (_options.tracePropagationTargets || _options.tracingOrigins)
+ );
+ }
+
+ this.options = {
+ ...DEFAULT_BROWSER_TRACING_OPTIONS,
+ ..._options,
+ };
+
+ // Special case: enableLongTask can be set in _experiments
+ // TODO (v8): Remove this in v8
+ if (this.options._experiments.enableLongTask !== undefined) {
+ this.options.enableLongTask = this.options._experiments.enableLongTask;
+ }
+
+ // TODO (v8): remove this block after tracingOrigins is removed
+ // Set tracePropagationTargets to tracingOrigins if specified by the user
+ // In case both are specified, tracePropagationTargets takes precedence
+ // eslint-disable-next-line deprecation/deprecation
+ if (_options && !_options.tracePropagationTargets && _options.tracingOrigins) {
+ // eslint-disable-next-line deprecation/deprecation
+ this.options.tracePropagationTargets = _options.tracingOrigins;
+ }
+
+ this._collectWebVitals = startTrackingWebVitals();
+ if (this.options.enableLongTask) {
+ startTrackingLongTasks();
+ }
+ if (this.options._experiments.enableInteractions) {
+ startTrackingInteractions();
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ setupOnce(_, getCurrentHub) {
+ this._getCurrentHub = getCurrentHub;
+ const hub = getCurrentHub();
+ const client = hub.getClient();
+ const clientOptions = client && client.getOptions();
+
+ const {
+ routingInstrumentation: instrumentRouting,
+ startTransactionOnLocationChange,
+ startTransactionOnPageLoad,
+ markBackgroundTransactions,
+ traceFetch,
+ traceXHR,
+ shouldCreateSpanForRequest,
+ _experiments,
+ } = this.options;
+
+ const clientOptionsTracePropagationTargets = clientOptions && clientOptions.tracePropagationTargets;
+ // There are three ways to configure tracePropagationTargets:
+ // 1. via top level client option `tracePropagationTargets`
+ // 2. via BrowserTracing option `tracePropagationTargets`
+ // 3. via BrowserTracing option `tracingOrigins` (deprecated)
+ //
+ // To avoid confusion, favour top level client option `tracePropagationTargets`, and fallback to
+ // BrowserTracing option `tracePropagationTargets` and then `tracingOrigins` (deprecated).
+ // This is done as it minimizes bundle size (we don't have to have undefined checks).
+ //
+ // If both 1 and either one of 2 or 3 are set (from above), we log out a warning.
+ const tracePropagationTargets = clientOptionsTracePropagationTargets || this.options.tracePropagationTargets;
+ if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && this._hasSetTracePropagationTargets && clientOptionsTracePropagationTargets) {
+ logger.warn(
+ '[Tracing] The `tracePropagationTargets` option was set in the BrowserTracing integration and top level `Sentry.init`. The top level `Sentry.init` value is being used.',
+ );
+ }
+
+ instrumentRouting(
+ (context) => {
+ const transaction = this._createRouteTransaction(context);
+
+ this.options._experiments.onStartRouteTransaction &&
+ this.options._experiments.onStartRouteTransaction(transaction, context, getCurrentHub);
+
+ return transaction;
+ },
+ startTransactionOnPageLoad,
+ startTransactionOnLocationChange,
+ );
+
+ if (markBackgroundTransactions) {
+ registerBackgroundTabDetection();
+ }
+
+ if (_experiments.enableInteractions) {
+ this._registerInteractionListener();
+ }
+
+ instrumentOutgoingRequests({
+ traceFetch,
+ traceXHR,
+ tracePropagationTargets,
+ shouldCreateSpanForRequest,
+ _experiments: {
+ enableHTTPTimings: _experiments.enableHTTPTimings,
+ },
+ });
+ }
+
+ /** Create routing idle transaction. */
+ _createRouteTransaction(context) {
+ if (!this._getCurrentHub) {
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
+ logger.warn(`[Tracing] Did not create ${context.op} transaction because _getCurrentHub is invalid.`);
+ return undefined;
+ }
+
+ const { beforeNavigate, idleTimeout, finalTimeout, heartbeatInterval } = this.options;
+
+ const isPageloadTransaction = context.op === 'pageload';
+
+ const sentryTraceMetaTagValue = isPageloadTransaction ? getMetaContent('sentry-trace') : null;
+ const baggageMetaTagValue = isPageloadTransaction ? getMetaContent('baggage') : null;
+
+ const traceParentData = sentryTraceMetaTagValue ? extractTraceparentData(sentryTraceMetaTagValue) : undefined;
+ const dynamicSamplingContext = baggageMetaTagValue
+ ? baggageHeaderToDynamicSamplingContext(baggageMetaTagValue)
+ : undefined;
+
+ const expandedContext = {
+ ...context,
+ ...traceParentData,
+ metadata: {
+ ...context.metadata,
+ dynamicSamplingContext: traceParentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
+ },
+ trimEnd: true,
+ };
+
+ const modifiedContext = typeof beforeNavigate === 'function' ? beforeNavigate(expandedContext) : expandedContext;
+
+ // For backwards compatibility reasons, beforeNavigate can return undefined to "drop" the transaction (prevent it
+ // from being sent to Sentry).
+ const finalContext = modifiedContext === undefined ? { ...expandedContext, sampled: false } : modifiedContext;
+
+ // If `beforeNavigate` set a custom name, record that fact
+ finalContext.metadata =
+ finalContext.name !== expandedContext.name
+ ? { ...finalContext.metadata, source: 'custom' }
+ : finalContext.metadata;
+
+ this._latestRouteName = finalContext.name;
+ this._latestRouteSource = finalContext.metadata && finalContext.metadata.source;
+
+ if (finalContext.sampled === false) {
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
+ logger.log(`[Tracing] Will not send ${finalContext.op} transaction because of beforeNavigate.`);
+ }
+
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log(`[Tracing] Starting ${finalContext.op} transaction on scope`);
+
+ const hub = this._getCurrentHub();
+ const { location } = WINDOW;
+
+ const idleTransaction = startIdleTransaction(
+ hub,
+ finalContext,
+ idleTimeout,
+ finalTimeout,
+ true,
+ { location }, // for use in the tracesSampler
+ heartbeatInterval,
+ );
+ idleTransaction.registerBeforeFinishCallback(transaction => {
+ this._collectWebVitals();
+ addPerformanceEntries(transaction);
+ });
+
+ return idleTransaction ;
+ }
+
+ /** Start listener for interaction transactions */
+ _registerInteractionListener() {
+ let inflightInteractionTransaction;
+ const registerInteractionTransaction = () => {
+ const { idleTimeout, finalTimeout, heartbeatInterval } = this.options;
+ const op = 'ui.action.click';
+
+ const currentTransaction = getActiveTransaction();
+ if (currentTransaction && currentTransaction.op && ['navigation', 'pageload'].includes(currentTransaction.op)) {
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
+ logger.warn(
+ `[Tracing] Did not create ${op} transaction because a pageload or navigation transaction is in progress.`,
+ );
+ return undefined;
+ }
+
+ if (inflightInteractionTransaction) {
+ inflightInteractionTransaction.setFinishReason('interactionInterrupted');
+ inflightInteractionTransaction.finish();
+ inflightInteractionTransaction = undefined;
+ }
+
+ if (!this._getCurrentHub) {
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn(`[Tracing] Did not create ${op} transaction because _getCurrentHub is invalid.`);
+ return undefined;
+ }
+
+ if (!this._latestRouteName) {
+ (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
+ logger.warn(`[Tracing] Did not create ${op} transaction because _latestRouteName is missing.`);
+ return undefined;
+ }
+
+ const hub = this._getCurrentHub();
+ const { location } = WINDOW;
+
+ const context = {
+ name: this._latestRouteName,
+ op,
+ trimEnd: true,
+ metadata: {
+ source: this._latestRouteSource || 'url',
+ },
+ };
+
+ inflightInteractionTransaction = startIdleTransaction(
+ hub,
+ context,
+ idleTimeout,
+ finalTimeout,
+ true,
+ { location }, // for use in the tracesSampler
+ heartbeatInterval,
+ );
+ };
+
+ ['click'].forEach(type => {
+ addEventListener(type, registerInteractionTransaction, { once: false, capture: true });
+ });
+ }
+}
+
+/** Returns the value of a meta tag */
+function getMetaContent(metaName) {
+ // Can't specify generic to `getDomElement` because tracing can be used
+ // in a variety of environments, have to disable `no-unsafe-member-access`
+ // as a result.
+ const metaTag = getDomElement(`meta[name=${metaName}]`);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ return metaTag ? metaTag.getAttribute('content') : null;
+}
+
+export { BROWSER_TRACING_INTEGRATION_ID, BrowserTracing, getMetaContent };
+//# sourceMappingURL=browsertracing.js.map