UNPKG

@sentry/react-native

Version:
106 lines 4.55 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'); } }); } export const SPAN_THREAD_NAME = 'thread.name'; export const SPAN_THREAD_NAME_MAIN = 'main'; export const SPAN_THREAD_NAME_JAVASCRIPT = 'javascript'; /** * Adds Javascript thread info to spans. * Ref: https://reactnative.dev/architecture/threading-model */ export function addThreadInfoToSpan(client) { client.on('spanStart', (span) => { var _a; if (!((_a = spanToJSON(span).data) === null || _a === void 0 ? void 0 : _a[SPAN_THREAD_NAME])) { span.setAttribute(SPAN_THREAD_NAME, SPAN_THREAD_NAME_JAVASCRIPT); } }); } /** * Sets the Main thread info to the span. */ export function setMainThreadInfo(spanJSON) { spanJSON.data = spanJSON.data || {}; spanJSON.data[SPAN_THREAD_NAME] = SPAN_THREAD_NAME_MAIN; return spanJSON; } //# sourceMappingURL=span.js.map