UNPKG

@sentry/react-native

Version:
83 lines 3.77 kB
import { generatePropagationContext, getActiveSpan, getClient, getCurrentScope, logger, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SentryNonRecordingSpan, SPAN_STATUS_ERROR, spanToJSON, startIdleSpan as coreStartIdleSpan, } from '@sentry/core'; import { isRootSpan } from '../utils/span'; import { adjustTransactionDuration, cancelInBackground } from './onSpanEndUtils'; import { SPAN_ORIGIN_AUTO_INTERACTION, SPAN_ORIGIN_AUTO_NAVIGATION_CUSTOM, SPAN_ORIGIN_MANUAL_INTERACTION, } from './origin'; export const DEFAULT_NAVIGATION_SPAN_NAME = 'Route Change'; export const defaultIdleOptions = { idleTimeout: 1000, finalTimeout: 600000, }; export const startIdleNavigationSpan = (startSpanOption, { finalTimeout = defaultIdleOptions.finalTimeout, idleTimeout = defaultIdleOptions.idleTimeout, } = {}) => { const client = getClient(); if (!client) { logger.warn(`[startIdleNavigationSpan] Can't create route change span, missing client.`); return undefined; } const activeSpan = getActiveSpan(); clearActiveSpanFromScope(getCurrentScope()); if (activeSpan && isRootSpan(activeSpan) && isSentryInteractionSpan(activeSpan)) { logger.log(`[startIdleNavigationSpan] Canceling ${spanToJSON(activeSpan).op} transaction because of a new navigation root span.`); activeSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'cancelled' }); activeSpan.end(); } const finalStartStapOptions = Object.assign(Object.assign({}, getDefaultIdleNavigationSpanOptions()), startSpanOption); const idleSpan = startIdleSpan(finalStartStapOptions, { finalTimeout, idleTimeout }); logger.log(`[startIdleNavigationSpan] Starting ${finalStartStapOptions.op || 'unknown op'} transaction "${finalStartStapOptions.name}" on scope`); adjustTransactionDuration(client, idleSpan, finalTimeout); idleSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_NAVIGATION_CUSTOM); return idleSpan; }; /** * Starts an idle span from `@sentry/core` with React Native application * context awareness. * * - Span will be started with new propagation context. * - Span will be canceled if the app goes to background. */ export const startIdleSpan = (startSpanOption, { finalTimeout, idleTimeout }) => { const client = getClient(); if (!client) { logger.warn(`[startIdleSpan] Can't create idle span, missing client.`); return new SentryNonRecordingSpan(); } getCurrentScope().setPropagationContext(generatePropagationContext()); const span = coreStartIdleSpan(startSpanOption, { finalTimeout, idleTimeout }); cancelInBackground(client, span); return span; }; /** * Returns the default options for the idle navigation span. */ export function getDefaultIdleNavigationSpanOptions() { return { name: DEFAULT_NAVIGATION_SPAN_NAME, op: 'navigation', forceTransaction: true, scope: getCurrentScope(), }; } /** * Checks if the span is a Sentry User Interaction span. */ export function isSentryInteractionSpan(span) { return [SPAN_ORIGIN_AUTO_INTERACTION, SPAN_ORIGIN_MANUAL_INTERACTION].includes(spanToJSON(span).origin); } export const SCOPE_SPAN_FIELD = '_sentrySpan'; /** * Removes the active span from the scope. */ export function clearActiveSpanFromScope(scope) { // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete scope[SCOPE_SPAN_FIELD]; } /** * Ensures that all created spans have an operation name. */ export function addDefaultOpForSpanFrom(client) { client.on('spanStart', (span) => { if (!spanToJSON(span).op) { span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'default'); } }); } //# sourceMappingURL=span.js.map