diff options
| author | rxliuli <rxliuli@gmail.com> | 2025-11-04 05:03:50 +0800 |
|---|---|---|
| committer | rxliuli <rxliuli@gmail.com> | 2025-11-04 05:03:50 +0800 |
| commit | bce557cc2dc767628bed6aac87301a1be7c5431b (patch) | |
| tree | b51a051228d01fe3306cd7626d4a96768aadb944 /shared/logger/node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js | |
init commit
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.js | 300 |
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 |
