@sentry/react-native 8.5.0 → 8.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RNSentry.podspec +1 -1
- package/android/expo-handler/build.gradle +20 -0
- package/android/expo-handler/src/main/java/io/sentry/react/expo/SentryExpoPackage.java +22 -0
- package/android/expo-handler/src/main/java/io/sentry/react/expo/SentryReactNativeHostHandler.java +48 -0
- package/android/expo-stubs/README.md +7 -0
- package/android/expo-stubs/build.gradle +23 -0
- package/android/expo-stubs/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/expo-stubs/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/android/expo-stubs/gradlew +251 -0
- package/android/expo-stubs/gradlew.bat +94 -0
- package/android/expo-stubs/settings.gradle +1 -0
- package/android/expo-stubs/src/main/java/expo/modules/core/interfaces/Package.java +11 -0
- package/android/expo-stubs/src/main/java/expo/modules/core/interfaces/ReactNativeHostHandler.java +7 -0
- package/android/libs/expo-stubs.jar +0 -0
- package/android/libs/replay-stubs.jar +0 -0
- package/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +15 -11
- package/android/src/main/java/io/sentry/react/RNSentryVersion.java +1 -1
- package/dist/js/NativeLogListener.js.map +1 -1
- package/dist/js/RNSentryReplayMaskNativeComponent.d.ts.map +1 -1
- package/dist/js/RNSentryReplayUnmaskNativeComponent.d.ts.map +1 -1
- package/dist/js/breadcrumb.js.map +1 -1
- package/dist/js/client.js.map +1 -1
- package/dist/js/feedback/FeedbackButton.js.map +1 -1
- package/dist/js/feedback/FeedbackWidget.js +6 -6
- package/dist/js/feedback/FeedbackWidget.js.map +1 -1
- package/dist/js/feedback/FeedbackWidget.styles.d.ts.map +1 -1
- package/dist/js/feedback/FeedbackWidgetManager.js.map +1 -1
- package/dist/js/feedback/FeedbackWidgetProvider.js.map +1 -1
- package/dist/js/feedback/ScreenshotButton.d.ts +1 -1
- package/dist/js/feedback/ScreenshotButton.js.map +1 -1
- package/dist/js/feedback/ShakeToReportBug.js.map +1 -1
- package/dist/js/feedback/defaults.js.map +1 -1
- package/dist/js/feedback/integration.d.ts +2 -2
- package/dist/js/feedback/integration.d.ts.map +1 -1
- package/dist/js/feedback/integration.js.map +1 -1
- package/dist/js/feedback/lazy.js.map +1 -1
- package/dist/js/feedback/utils.d.ts.map +1 -1
- package/dist/js/feedback/utils.js.map +1 -1
- package/dist/js/integrations/appRegistry.d.ts.map +1 -1
- package/dist/js/integrations/appRegistry.js.map +1 -1
- package/dist/js/integrations/breadcrumbs.d.ts.map +1 -1
- package/dist/js/integrations/debugsymbolicator.js +3 -3
- package/dist/js/integrations/debugsymbolicator.js.map +1 -1
- package/dist/js/integrations/debugsymbolicatorutils.js.map +1 -1
- package/dist/js/integrations/default.js +1 -1
- package/dist/js/integrations/default.js.map +1 -1
- package/dist/js/integrations/devicecontext.js +1 -1
- package/dist/js/integrations/devicecontext.js.map +1 -1
- package/dist/js/integrations/expoconstants.js.map +1 -1
- package/dist/js/integrations/expocontext.js.map +1 -1
- package/dist/js/integrations/expoupdateslistener.js.map +1 -1
- package/dist/js/integrations/logEnricherIntegration.js +1 -1
- package/dist/js/integrations/logEnricherIntegration.js.map +1 -1
- package/dist/js/integrations/modulesloader.js.map +1 -1
- package/dist/js/integrations/nativelinkederrors.d.ts.map +1 -1
- package/dist/js/integrations/nativelinkederrors.js +1 -0
- package/dist/js/integrations/nativelinkederrors.js.map +1 -1
- package/dist/js/integrations/primitiveTagIntegration.js.map +1 -1
- package/dist/js/integrations/reactnativeerrorhandlers.d.ts.map +1 -1
- package/dist/js/integrations/reactnativeerrorhandlers.js.map +1 -1
- package/dist/js/integrations/reactnativeerrorhandlersutils.js.map +1 -1
- package/dist/js/integrations/reactnativeinfo.js.map +1 -1
- package/dist/js/integrations/release.js +1 -1
- package/dist/js/integrations/release.js.map +1 -1
- package/dist/js/integrations/rewriteframes.js.map +1 -1
- package/dist/js/integrations/screenshot.js +1 -1
- package/dist/js/integrations/screenshot.js.map +1 -1
- package/dist/js/integrations/sdkinfo.js.map +1 -1
- package/dist/js/integrations/spotlight.js.map +1 -1
- package/dist/js/integrations/viewhierarchy.js +1 -1
- package/dist/js/integrations/viewhierarchy.js.map +1 -1
- package/dist/js/misc.js.map +1 -1
- package/dist/js/options.d.ts +1 -1
- package/dist/js/options.js.map +1 -1
- package/dist/js/playground/examples.js.map +1 -1
- package/dist/js/playground/modal.d.ts +2 -2
- package/dist/js/playground/modal.d.ts.map +1 -1
- package/dist/js/playground/modal.js +6 -6
- package/dist/js/playground/modal.js.map +1 -1
- package/dist/js/profiling/cache.js.map +1 -1
- package/dist/js/profiling/convertHermesProfile.js.map +1 -1
- package/dist/js/profiling/debugid.js.map +1 -1
- package/dist/js/profiling/integration.d.ts.map +1 -1
- package/dist/js/profiling/integration.js.map +1 -1
- package/dist/js/profiling/utils.js.map +1 -1
- package/dist/js/replay/CustomMask.d.ts.map +1 -1
- package/dist/js/replay/CustomMask.js.map +1 -1
- package/dist/js/replay/CustomMask.web.d.ts.map +1 -1
- package/dist/js/replay/browserReplay.d.ts.map +1 -1
- package/dist/js/replay/browserReplay.js.map +1 -1
- package/dist/js/replay/mobilereplay.d.ts.map +1 -1
- package/dist/js/replay/mobilereplay.js +21 -2
- package/dist/js/replay/mobilereplay.js.map +1 -1
- package/dist/js/replay/networkUtils.d.ts +0 -1
- package/dist/js/replay/networkUtils.d.ts.map +1 -1
- package/dist/js/replay/networkUtils.js.map +1 -1
- package/dist/js/replay/xhrUtils.js.map +1 -1
- package/dist/js/scopeSync.js.map +1 -1
- package/dist/js/sdk.d.ts.map +1 -1
- package/dist/js/sdk.js +4 -2
- package/dist/js/sdk.js.map +1 -1
- package/dist/js/tools/ModulesCollector.js.map +1 -1
- package/dist/js/tools/easBuildHooks.js +13 -14
- package/dist/js/tools/easBuildHooks.js.map +1 -1
- package/dist/js/tools/enableLogger.js +1 -2
- package/dist/js/tools/enableLogger.js.map +1 -1
- package/dist/js/tools/metroMiddleware.d.ts.map +1 -1
- package/dist/js/tools/metroMiddleware.js.map +1 -1
- package/dist/js/tools/metroconfig.js +6 -7
- package/dist/js/tools/metroconfig.js.map +1 -1
- package/dist/js/tools/sentryBabelTransformerUtils.js +7 -7
- package/dist/js/tools/sentryBabelTransformerUtils.js.map +1 -1
- package/dist/js/tools/sentryMetroSerializer.d.ts.map +1 -1
- package/dist/js/tools/sentryMetroSerializer.js +2 -2
- package/dist/js/tools/sentryMetroSerializer.js.map +1 -1
- package/dist/js/tools/sentryOptionsSerializer.js +1 -2
- package/dist/js/tools/sentryOptionsSerializer.js.map +1 -1
- package/dist/js/tools/sentryReleaseInjector.d.ts +1 -1
- package/dist/js/tools/sentryReleaseInjector.d.ts.map +1 -1
- package/dist/js/tools/sentryReleaseInjector.js.map +1 -1
- package/dist/js/tools/utils.d.ts.map +1 -1
- package/dist/js/tools/utils.js +7 -7
- package/dist/js/tools/utils.js.map +1 -1
- package/dist/js/tools/vendor/metro/countLines.d.ts.map +1 -1
- package/dist/js/tools/vendor/metro/utils.d.ts.map +1 -1
- package/dist/js/tools/vendor/metro/utils.js.map +1 -1
- package/dist/js/touchevents.d.ts.map +1 -1
- package/dist/js/touchevents.js +2 -0
- package/dist/js/touchevents.js.map +1 -1
- package/dist/js/tracing/expoAsset.js.map +1 -1
- package/dist/js/tracing/expoImage.js.map +1 -1
- package/dist/js/tracing/expoRouter.js.map +1 -1
- package/dist/js/tracing/gesturetracing.js.map +1 -1
- package/dist/js/tracing/integrations/appStart.d.ts +1 -1
- package/dist/js/tracing/integrations/appStart.d.ts.map +1 -1
- package/dist/js/tracing/integrations/appStart.js +5 -5
- package/dist/js/tracing/integrations/appStart.js.map +1 -1
- package/dist/js/tracing/integrations/nativeFrames.d.ts.map +1 -1
- package/dist/js/tracing/integrations/nativeFrames.js +4 -1
- package/dist/js/tracing/integrations/nativeFrames.js.map +1 -1
- package/dist/js/tracing/integrations/stalltracking.d.ts +1 -1
- package/dist/js/tracing/integrations/stalltracking.d.ts.map +1 -1
- package/dist/js/tracing/integrations/stalltracking.js +4 -1
- package/dist/js/tracing/integrations/stalltracking.js.map +1 -1
- package/dist/js/tracing/integrations/timeToDisplayIntegration.js +14 -14
- package/dist/js/tracing/integrations/timeToDisplayIntegration.js.map +1 -1
- package/dist/js/tracing/integrations/userInteraction.d.ts.map +1 -1
- package/dist/js/tracing/integrations/userInteraction.js.map +1 -1
- package/dist/js/tracing/onSpanEndUtils.d.ts.map +1 -1
- package/dist/js/tracing/onSpanEndUtils.js +20 -13
- package/dist/js/tracing/onSpanEndUtils.js.map +1 -1
- package/dist/js/tracing/reactnativenavigation.d.ts.map +1 -1
- package/dist/js/tracing/reactnativenavigation.js.map +1 -1
- package/dist/js/tracing/reactnativeprofiler.js.map +1 -1
- package/dist/js/tracing/reactnativetracing.d.ts.map +1 -1
- package/dist/js/tracing/reactnativetracing.js.map +1 -1
- package/dist/js/tracing/reactnavigation.d.ts +3 -0
- package/dist/js/tracing/reactnavigation.d.ts.map +1 -1
- package/dist/js/tracing/reactnavigation.js +4 -2
- package/dist/js/tracing/reactnavigation.js.map +1 -1
- package/dist/js/tracing/span.d.ts +2 -17
- package/dist/js/tracing/span.d.ts.map +1 -1
- package/dist/js/tracing/span.js.map +1 -1
- package/dist/js/tracing/timeToDisplayFallback.d.ts.map +1 -1
- package/dist/js/tracing/timetodisplay.js.map +1 -1
- package/dist/js/tracing/timetodisplaynative.d.ts.map +1 -1
- package/dist/js/tracing/timetodisplaynative.js.map +1 -1
- package/dist/js/tracing/utils.js.map +1 -1
- package/dist/js/transports/encodePolyfill.d.ts +1 -1
- package/dist/js/transports/encodePolyfill.d.ts.map +1 -1
- package/dist/js/transports/encodePolyfill.js.map +1 -1
- package/dist/js/transports/native.js.map +1 -1
- package/dist/js/utils/AsyncExpiringMap.js.map +1 -1
- package/dist/js/utils/encode.js.map +1 -1
- package/dist/js/utils/environment.js.map +1 -1
- package/dist/js/utils/ignorerequirecyclelogs.js.map +1 -1
- package/dist/js/utils/normalize.js.map +1 -1
- package/dist/js/utils/outcome.js.map +1 -1
- package/dist/js/utils/primitiveConverter.js.map +1 -1
- package/dist/js/utils/release.js.map +1 -1
- package/dist/js/utils/rnlibraries.js.map +1 -1
- package/dist/js/utils/safe.js.map +1 -1
- package/dist/js/utils/worldwide.d.ts +0 -1
- package/dist/js/utils/worldwide.d.ts.map +1 -1
- package/dist/js/utils/xhr.d.ts +0 -1
- package/dist/js/utils/xhr.d.ts.map +1 -1
- package/dist/js/utils/xhr.js.map +1 -1
- package/dist/js/vendor/base64-js/fromByteArray.js.map +1 -1
- package/dist/js/vendor/buffer/utf8ToBytes.js.map +1 -1
- package/dist/js/version.d.ts +1 -1
- package/dist/js/version.js +1 -1
- package/dist/js/version.js.map +1 -1
- package/dist/js/wrapper.d.ts.map +1 -1
- package/dist/js/wrapper.js +5 -6
- package/dist/js/wrapper.js.map +1 -1
- package/expo-module.config.json +7 -0
- package/ios/RNSentryStart.m +4 -1
- package/ios/RNSentryVersion.m +1 -1
- package/package.json +10 -10
- package/ts3.8/dist/js/feedback/ScreenshotButton.d.ts +1 -1
- package/ts3.8/dist/js/feedback/integration.d.ts +2 -2
- package/ts3.8/dist/js/options.d.ts +1 -1
- package/ts3.8/dist/js/playground/modal.d.ts +2 -2
- package/ts3.8/dist/js/replay/networkUtils.d.ts +0 -1
- package/ts3.8/dist/js/tracing/integrations/appStart.d.ts +1 -1
- package/ts3.8/dist/js/tracing/integrations/stalltracking.d.ts +1 -1
- package/ts3.8/dist/js/tracing/reactnavigation.d.ts +3 -0
- package/ts3.8/dist/js/tracing/span.d.ts +2 -17
- package/ts3.8/dist/js/transports/encodePolyfill.d.ts +1 -1
- package/ts3.8/dist/js/utils/worldwide.d.ts +0 -1
- package/ts3.8/dist/js/utils/xhr.d.ts +0 -1
- package/ts3.8/dist/js/version.d.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nativeFrames.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/nativeFrames.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Client, Event, Integration, Measurements, MeasurementUnit, Span } from '@sentry/core';\nimport { debug, getRootSpan, spanToJSON, timestampInSeconds } from '@sentry/core';\nimport type { NativeFramesResponse } from '../../NativeRNSentry';\nimport { AsyncExpiringMap } from '../../utils/AsyncExpiringMap';\nimport { isRootSpan } from '../../utils/span';\nimport { NATIVE } from '../../wrapper';\n\n/**\n * Timeout from the start of a span to fetching the associated native frames.\n */\nconst FETCH_FRAMES_TIMEOUT_MS = 2_000;\n\n/**\n * This is the time end frames data from the native layer will be\n * kept in memory and waiting for the event processing. This ensures that spans\n * which are never processed are not leaking memory.\n */\nconst END_FRAMES_TIMEOUT_MS = 2_000;\n\n/**\n * This is the time start frames data from the native layer will be\n * kept in memory and waiting for span end. This ensures that spans\n * which never end or are not processed are not leaking memory.\n */\nconst START_FRAMES_TIMEOUT_MS = 60_000;\n\n/**\n * A margin of error of 50ms is allowed for the async native bridge call.\n * Anything larger would reduce the accuracy of our frames measurements.\n */\nconst MARGIN_OF_ERROR_SECONDS = 0.05;\n\nconst INTEGRATION_NAME = 'NativeFrames';\n\nexport interface FramesMeasurements extends Measurements {\n frames_total: { value: number; unit: MeasurementUnit };\n frames_slow: { value: number; unit: MeasurementUnit };\n frames_frozen: { value: number; unit: MeasurementUnit };\n}\n\ninterface NativeFramesResponseWithTimestamp {\n timestamp: number;\n nativeFrames: NativeFramesResponse;\n}\n\nexport const createNativeFramesIntegrations = (enable: boolean | undefined): Integration | undefined => {\n if (!enable && NATIVE.enableNative) {\n // On Android this will free up resource when JS reloaded (native modules stay) and thus JS side of the SDK reinitialized.\n NATIVE.disableNativeFramesTracking();\n return undefined;\n }\n\n return nativeFramesIntegration();\n};\n\n/**\n * Instrumentation to add native slow/frozen frames measurements onto transactions\n * and frame data (frames.total, frames.slow, frames.frozen) onto all spans.\n */\nexport const nativeFramesIntegration = (): Integration => {\n /** The native frames at the finish time of the most recent child span, keyed by root span ID.\n * Stores promises so the data is available for processEvent to await even before\n * the async native bridge call completes. */\n const _lastChildSpanEndFramesByRootSpan: AsyncExpiringMap<string, NativeFramesResponseWithTimestamp | null> =\n new AsyncExpiringMap({ ttl: START_FRAMES_TIMEOUT_MS });\n const _spanToNativeFramesAtStartMap: AsyncExpiringMap<string, NativeFramesResponse | null> = new AsyncExpiringMap({\n ttl: START_FRAMES_TIMEOUT_MS,\n });\n const _spanToNativeFramesAtEndMap: AsyncExpiringMap<string, NativeFramesResponseWithTimestamp | null> =\n new AsyncExpiringMap({ ttl: END_FRAMES_TIMEOUT_MS });\n\n /**\n * Hooks into the client start and end span events.\n */\n const setup = (client: Client): void => {\n if (!NATIVE.enableNative) {\n debug.warn(\n `[${INTEGRATION_NAME}] This is not available on the Web, Expo Go and other platforms without native modules.`,\n );\n return undefined;\n }\n\n NATIVE.enableNativeFramesTracking();\n client.on('spanStart', fetchStartFramesForSpan);\n client.on('spanEnd', fetchEndFramesForSpan);\n };\n\n const fetchStartFramesForSpan = (span: Span): void => {\n const spanId = span.spanContext().spanId;\n const spanType = isRootSpan(span) ? 'root' : 'child';\n debug.log(`[${INTEGRATION_NAME}] Fetching frames for ${spanType} span start (${spanId}).`);\n\n _spanToNativeFramesAtStartMap.set(\n spanId,\n new Promise<NativeFramesResponse | null>(resolve => {\n fetchNativeFrames()\n .then(frames => resolve(frames))\n .then(undefined, error => {\n debug.log(`[${INTEGRATION_NAME}] Error while fetching native frames.`, error);\n resolve(null);\n });\n }),\n );\n };\n\n /**\n * Fetches end frames for a span and attaches frame data as span attributes.\n *\n * Note: This makes one native bridge call per span end. While this creates O(n) calls\n * for n spans, it's necessary for accuracy. Frame counts are cumulative and continuously\n * incrementing, so each span needs the exact frame count at its end time. Caching would\n * produce incorrect deltas. The native bridge calls are async and non-blocking.\n */\n const fetchEndFramesForSpan = async (span: Span): Promise<void> => {\n const spanId = span.spanContext().spanId;\n const hasStartFrames = _spanToNativeFramesAtStartMap.has(spanId);\n\n if (!hasStartFrames) {\n // We don't have start frames, won't be able to calculate the difference.\n return;\n }\n\n // For child spans: immediately store a promise for fallback end frames before any awaits,\n // so processEvent can find and await it even if this async function hasn't completed yet.\n // Uses the actual span timestamp (not wall-clock time) so it matches the trimmed event.timestamp\n // for idle transactions. Scoped per root span to avoid concurrent transaction interference.\n let childEndFramesPromise: Promise<NativeFramesResponse> | undefined;\n if (!isRootSpan(span)) {\n const rootSpanId = getRootSpan(span).spanContext().spanId;\n const spanTimestamp = spanToJSON(span).timestamp;\n if (spanTimestamp) {\n childEndFramesPromise = fetchNativeFrames();\n _lastChildSpanEndFramesByRootSpan.set(\n rootSpanId,\n childEndFramesPromise\n .then(frames => ({ timestamp: spanTimestamp, nativeFrames: frames }))\n .then(undefined, () => null),\n );\n }\n }\n\n if (isRootSpan(span)) {\n // Root spans: Store end frames for transaction measurements (backward compatibility)\n const timestamp = timestampInSeconds();\n debug.log(`[${INTEGRATION_NAME}] Fetch frames for root span end (${spanId}).`);\n _spanToNativeFramesAtEndMap.set(\n spanId,\n new Promise<NativeFramesResponseWithTimestamp | null>(resolve => {\n fetchNativeFrames()\n .then(frames => {\n resolve({\n timestamp,\n nativeFrames: frames,\n });\n })\n .then(undefined, error => {\n debug.log(`[${INTEGRATION_NAME}] Error while fetching native frames.`, error);\n resolve(null);\n });\n }),\n );\n }\n\n // All spans (root and child): Attach frame data as span attributes\n try {\n const startFrames = await _spanToNativeFramesAtStartMap.get(spanId);\n if (!startFrames) {\n debug.log(`[${INTEGRATION_NAME}] No start frames found for span ${spanId}, skipping frame data.`);\n return;\n }\n\n // For child spans, reuse the already-kicked-off promise to avoid a redundant native bridge call.\n // For root spans, this is the second call to fetchNativeFrames() for the same span.\n // The calls are very close together (microseconds apart), so inconsistency is minimal.\n const endFrames = childEndFramesPromise ? await childEndFramesPromise : await fetchNativeFrames();\n\n // Calculate deltas\n const totalFrames = endFrames.totalFrames - startFrames.totalFrames;\n const slowFrames = endFrames.slowFrames - startFrames.slowFrames;\n const frozenFrames = endFrames.frozenFrames - startFrames.frozenFrames;\n\n // Only attach if we have meaningful data\n if (totalFrames > 0 || slowFrames > 0 || frozenFrames > 0) {\n span.setAttribute('frames.total', totalFrames);\n span.setAttribute('frames.slow', slowFrames);\n span.setAttribute('frames.frozen', frozenFrames);\n debug.log(\n `[${INTEGRATION_NAME}] Attached frame data to span ${spanId}: total=${totalFrames}, slow=${slowFrames}, frozen=${frozenFrames}`,\n );\n }\n } catch (error) {\n debug.log(`[${INTEGRATION_NAME}] Error while capturing end frames for span ${spanId}.`, error);\n }\n };\n\n const processEvent = async (event: Event): Promise<Event> => {\n if (\n event.type !== 'transaction' ||\n !event.transaction ||\n !event.contexts?.trace ||\n !event.timestamp ||\n !event.contexts.trace.span_id\n ) {\n return event;\n }\n\n const traceOp = event.contexts.trace.op;\n const spanId = event.contexts.trace.span_id;\n const startFrames = await _spanToNativeFramesAtStartMap.pop(spanId);\n if (!startFrames) {\n debug.warn(\n `[${INTEGRATION_NAME}] Start frames of transaction ${event.transaction} (eventId, ${event.event_id}) are missing, but the transaction already ended.`,\n );\n return event;\n }\n\n const endFrames = await _spanToNativeFramesAtEndMap.pop(spanId);\n const lastChildFrames = await _lastChildSpanEndFramesByRootSpan.pop(spanId);\n let finalEndFrames: NativeFramesResponse | undefined;\n\n if (endFrames && isClose(endFrames.timestamp, event.timestamp)) {\n // Must be in the margin of error of the actual transaction finish time (finalEndTimestamp)\n debug.log(`[${INTEGRATION_NAME}] Using frames from root span end (spanId, ${spanId}).`);\n finalEndFrames = endFrames.nativeFrames;\n } else if (lastChildFrames && isClose(lastChildFrames.timestamp, event.timestamp)) {\n // Fallback to the last child span finish if it is within the margin of error of the actual finish timestamp.\n // This handles idle transactions where event.timestamp is trimmed to the last child span's end time.\n debug.log(`[${INTEGRATION_NAME}] Using native frames from last child span end (spanId, ${spanId}).`);\n finalEndFrames = lastChildFrames.nativeFrames;\n } else {\n debug.warn(\n `[${INTEGRATION_NAME}] Frames were collected within larger than margin of error delay for spanId (${spanId}). Dropping the inaccurate values.`,\n );\n return event;\n }\n\n const measurements = {\n frames_total: {\n value: finalEndFrames.totalFrames - startFrames.totalFrames,\n unit: 'none',\n },\n frames_frozen: {\n value: finalEndFrames.frozenFrames - startFrames.frozenFrames,\n unit: 'none',\n },\n frames_slow: {\n value: finalEndFrames.slowFrames - startFrames.slowFrames,\n unit: 'none',\n },\n };\n\n if (\n measurements.frames_frozen.value <= 0 &&\n measurements.frames_slow.value <= 0 &&\n measurements.frames_total.value <= 0\n ) {\n debug.warn(\n `[${INTEGRATION_NAME}] Detected zero slow or frozen frames. Not adding measurements to spanId (${spanId}).`,\n );\n return event;\n }\n\n debug.log(\n `[${INTEGRATION_NAME}] Adding measurements to ${traceOp} transaction ${event.transaction}: ${JSON.stringify(\n measurements,\n undefined,\n 2,\n )}`,\n );\n event.measurements = {\n ...(event.measurements ?? {}),\n ...measurements,\n };\n return event;\n };\n\n return {\n name: INTEGRATION_NAME,\n setup,\n processEvent,\n };\n};\n\nfunction fetchNativeFrames(): Promise<NativeFramesResponse> {\n return new Promise<NativeFramesResponse>((resolve, reject) => {\n let settled = false;\n\n const timeoutId = setTimeout(() => {\n if (!settled) {\n settled = true;\n reject('Fetching native frames took too long. Dropping frames.');\n }\n }, FETCH_FRAMES_TIMEOUT_MS);\n\n NATIVE.fetchNativeFrames()\n .then(value => {\n if (settled) {\n return;\n }\n clearTimeout(timeoutId);\n settled = true;\n\n if (!value) {\n reject('Native frames response is null.');\n return;\n }\n resolve(value);\n })\n .then(undefined, error => {\n if (settled) {\n return;\n }\n clearTimeout(timeoutId);\n settled = true;\n reject(error);\n });\n });\n}\n\nfunction isClose(t1: number, t2: number): boolean {\n return Math.abs(t1 - t2) < MARGIN_OF_ERROR_SECONDS;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"nativeFrames.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/nativeFrames.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Client, Event, Integration, Measurements, MeasurementUnit, Span } from '@sentry/core';\nimport { debug, getRootSpan, spanIsSampled, spanToJSON, timestampInSeconds } from '@sentry/core';\nimport type { NativeFramesResponse } from '../../NativeRNSentry';\nimport { AsyncExpiringMap } from '../../utils/AsyncExpiringMap';\nimport { isRootSpan } from '../../utils/span';\nimport { NATIVE } from '../../wrapper';\n\n/**\n * Timeout from the start of a span to fetching the associated native frames.\n */\nconst FETCH_FRAMES_TIMEOUT_MS = 2_000;\n\n/**\n * This is the time end frames data from the native layer will be\n * kept in memory and waiting for the event processing. This ensures that spans\n * which are never processed are not leaking memory.\n */\nconst END_FRAMES_TIMEOUT_MS = 2_000;\n\n/**\n * This is the time start frames data from the native layer will be\n * kept in memory and waiting for span end. This ensures that spans\n * which never end or are not processed are not leaking memory.\n */\nconst START_FRAMES_TIMEOUT_MS = 60_000;\n\n/**\n * A margin of error of 50ms is allowed for the async native bridge call.\n * Anything larger would reduce the accuracy of our frames measurements.\n */\nconst MARGIN_OF_ERROR_SECONDS = 0.05;\n\nconst INTEGRATION_NAME = 'NativeFrames';\n\nexport interface FramesMeasurements extends Measurements {\n frames_total: { value: number; unit: MeasurementUnit };\n frames_slow: { value: number; unit: MeasurementUnit };\n frames_frozen: { value: number; unit: MeasurementUnit };\n}\n\ninterface NativeFramesResponseWithTimestamp {\n timestamp: number;\n nativeFrames: NativeFramesResponse;\n}\n\nexport const createNativeFramesIntegrations = (enable: boolean | undefined): Integration | undefined => {\n if (!enable && NATIVE.enableNative) {\n // On Android this will free up resource when JS reloaded (native modules stay) and thus JS side of the SDK reinitialized.\n NATIVE.disableNativeFramesTracking();\n return undefined;\n }\n\n return nativeFramesIntegration();\n};\n\n/**\n * Instrumentation to add native slow/frozen frames measurements onto transactions\n * and frame data (frames.total, frames.slow, frames.frozen) onto all spans.\n */\nexport const nativeFramesIntegration = (): Integration => {\n /** The native frames at the finish time of the most recent child span, keyed by root span ID.\n * Stores promises so the data is available for processEvent to await even before\n * the async native bridge call completes. */\n const _lastChildSpanEndFramesByRootSpan: AsyncExpiringMap<string, NativeFramesResponseWithTimestamp | null> =\n new AsyncExpiringMap({ ttl: START_FRAMES_TIMEOUT_MS });\n const _spanToNativeFramesAtStartMap: AsyncExpiringMap<string, NativeFramesResponse | null> = new AsyncExpiringMap({\n ttl: START_FRAMES_TIMEOUT_MS,\n });\n const _spanToNativeFramesAtEndMap: AsyncExpiringMap<string, NativeFramesResponseWithTimestamp | null> =\n new AsyncExpiringMap({ ttl: END_FRAMES_TIMEOUT_MS });\n\n /**\n * Hooks into the client start and end span events.\n */\n const setup = (client: Client): void => {\n if (!NATIVE.enableNative) {\n debug.warn(\n `[${INTEGRATION_NAME}] This is not available on the Web, Expo Go and other platforms without native modules.`,\n );\n return undefined;\n }\n\n NATIVE.enableNativeFramesTracking();\n client.on('spanStart', fetchStartFramesForSpan);\n client.on('spanEnd', fetchEndFramesForSpan);\n };\n\n const fetchStartFramesForSpan = (span: Span): void => {\n if (!spanIsSampled(span)) {\n return;\n }\n\n const spanId = span.spanContext().spanId;\n const spanType = isRootSpan(span) ? 'root' : 'child';\n debug.log(`[${INTEGRATION_NAME}] Fetching frames for ${spanType} span start (${spanId}).`);\n\n _spanToNativeFramesAtStartMap.set(\n spanId,\n new Promise<NativeFramesResponse | null>(resolve => {\n fetchNativeFrames()\n .then(frames => resolve(frames))\n .then(undefined, error => {\n debug.log(`[${INTEGRATION_NAME}] Error while fetching native frames.`, error);\n resolve(null);\n });\n }),\n );\n };\n\n /**\n * Fetches end frames for a span and attaches frame data as span attributes.\n *\n * Note: This makes one native bridge call per span end. While this creates O(n) calls\n * for n spans, it's necessary for accuracy. Frame counts are cumulative and continuously\n * incrementing, so each span needs the exact frame count at its end time. Caching would\n * produce incorrect deltas. The native bridge calls are async and non-blocking.\n */\n const fetchEndFramesForSpan = async (span: Span): Promise<void> => {\n const spanId = span.spanContext().spanId;\n const hasStartFrames = _spanToNativeFramesAtStartMap.has(spanId);\n\n if (!hasStartFrames) {\n // We don't have start frames, won't be able to calculate the difference.\n return;\n }\n\n // For child spans: immediately store a promise for fallback end frames before any awaits,\n // so processEvent can find and await it even if this async function hasn't completed yet.\n // Uses the actual span timestamp (not wall-clock time) so it matches the trimmed event.timestamp\n // for idle transactions. Scoped per root span to avoid concurrent transaction interference.\n let childEndFramesPromise: Promise<NativeFramesResponse> | undefined;\n if (!isRootSpan(span)) {\n const rootSpanId = getRootSpan(span).spanContext().spanId;\n const spanTimestamp = spanToJSON(span).timestamp;\n if (spanTimestamp) {\n childEndFramesPromise = fetchNativeFrames();\n _lastChildSpanEndFramesByRootSpan.set(\n rootSpanId,\n childEndFramesPromise\n .then(frames => ({ timestamp: spanTimestamp, nativeFrames: frames }))\n .then(undefined, () => null),\n );\n }\n }\n\n if (isRootSpan(span)) {\n // Root spans: Store end frames for transaction measurements (backward compatibility)\n const timestamp = timestampInSeconds();\n debug.log(`[${INTEGRATION_NAME}] Fetch frames for root span end (${spanId}).`);\n _spanToNativeFramesAtEndMap.set(\n spanId,\n new Promise<NativeFramesResponseWithTimestamp | null>(resolve => {\n fetchNativeFrames()\n .then(frames => {\n resolve({\n timestamp,\n nativeFrames: frames,\n });\n })\n .then(undefined, error => {\n debug.log(`[${INTEGRATION_NAME}] Error while fetching native frames.`, error);\n resolve(null);\n });\n }),\n );\n }\n\n // All spans (root and child): Attach frame data as span attributes\n try {\n const startFrames = await _spanToNativeFramesAtStartMap.get(spanId);\n if (!startFrames) {\n debug.log(`[${INTEGRATION_NAME}] No start frames found for span ${spanId}, skipping frame data.`);\n return;\n }\n\n // For child spans, reuse the already-kicked-off promise to avoid a redundant native bridge call.\n // For root spans, this is the second call to fetchNativeFrames() for the same span.\n // The calls are very close together (microseconds apart), so inconsistency is minimal.\n const endFrames = childEndFramesPromise ? await childEndFramesPromise : await fetchNativeFrames();\n\n // Calculate deltas\n const totalFrames = endFrames.totalFrames - startFrames.totalFrames;\n const slowFrames = endFrames.slowFrames - startFrames.slowFrames;\n const frozenFrames = endFrames.frozenFrames - startFrames.frozenFrames;\n\n // Only attach if we have meaningful data\n if (totalFrames > 0 || slowFrames > 0 || frozenFrames > 0) {\n span.setAttribute('frames.total', totalFrames);\n span.setAttribute('frames.slow', slowFrames);\n span.setAttribute('frames.frozen', frozenFrames);\n debug.log(\n `[${INTEGRATION_NAME}] Attached frame data to span ${spanId}: total=${totalFrames}, slow=${slowFrames}, frozen=${frozenFrames}`,\n );\n }\n } catch (error) {\n debug.log(`[${INTEGRATION_NAME}] Error while capturing end frames for span ${spanId}.`, error);\n }\n };\n\n const processEvent = async (event: Event): Promise<Event> => {\n if (\n event.type !== 'transaction' ||\n !event.transaction ||\n !event.contexts?.trace ||\n !event.timestamp ||\n !event.contexts.trace.span_id\n ) {\n return event;\n }\n\n const traceOp = event.contexts.trace.op;\n const spanId = event.contexts.trace.span_id;\n const startFrames = await _spanToNativeFramesAtStartMap.pop(spanId);\n if (!startFrames) {\n debug.warn(\n `[${INTEGRATION_NAME}] Start frames of transaction ${event.transaction} (eventId, ${event.event_id}) are missing, but the transaction already ended.`,\n );\n return event;\n }\n\n const endFrames = await _spanToNativeFramesAtEndMap.pop(spanId);\n const lastChildFrames = await _lastChildSpanEndFramesByRootSpan.pop(spanId);\n let finalEndFrames: NativeFramesResponse | undefined;\n\n if (endFrames && isClose(endFrames.timestamp, event.timestamp)) {\n // Must be in the margin of error of the actual transaction finish time (finalEndTimestamp)\n debug.log(`[${INTEGRATION_NAME}] Using frames from root span end (spanId, ${spanId}).`);\n finalEndFrames = endFrames.nativeFrames;\n } else if (lastChildFrames && isClose(lastChildFrames.timestamp, event.timestamp)) {\n // Fallback to the last child span finish if it is within the margin of error of the actual finish timestamp.\n // This handles idle transactions where event.timestamp is trimmed to the last child span's end time.\n debug.log(`[${INTEGRATION_NAME}] Using native frames from last child span end (spanId, ${spanId}).`);\n finalEndFrames = lastChildFrames.nativeFrames;\n } else {\n debug.warn(\n `[${INTEGRATION_NAME}] Frames were collected within larger than margin of error delay for spanId (${spanId}). Dropping the inaccurate values.`,\n );\n return event;\n }\n\n const measurements = {\n frames_total: {\n value: finalEndFrames.totalFrames - startFrames.totalFrames,\n unit: 'none',\n },\n frames_frozen: {\n value: finalEndFrames.frozenFrames - startFrames.frozenFrames,\n unit: 'none',\n },\n frames_slow: {\n value: finalEndFrames.slowFrames - startFrames.slowFrames,\n unit: 'none',\n },\n };\n\n if (\n measurements.frames_frozen.value <= 0 &&\n measurements.frames_slow.value <= 0 &&\n measurements.frames_total.value <= 0\n ) {\n debug.warn(\n `[${INTEGRATION_NAME}] Detected zero slow or frozen frames. Not adding measurements to spanId (${spanId}).`,\n );\n return event;\n }\n\n debug.log(\n `[${INTEGRATION_NAME}] Adding measurements to ${traceOp} transaction ${event.transaction}: ${JSON.stringify(\n measurements,\n undefined,\n 2,\n )}`,\n );\n event.measurements = {\n ...(event.measurements ?? {}),\n ...measurements,\n };\n return event;\n };\n\n return {\n name: INTEGRATION_NAME,\n setup,\n processEvent,\n };\n};\n\nfunction fetchNativeFrames(): Promise<NativeFramesResponse> {\n return new Promise<NativeFramesResponse>((resolve, reject) => {\n let settled = false;\n\n const timeoutId = setTimeout(() => {\n if (!settled) {\n settled = true;\n reject('Fetching native frames took too long. Dropping frames.');\n }\n }, FETCH_FRAMES_TIMEOUT_MS);\n\n NATIVE.fetchNativeFrames()\n .then(value => {\n if (settled) {\n return;\n }\n clearTimeout(timeoutId);\n settled = true;\n\n if (!value) {\n reject('Native frames response is null.');\n return;\n }\n resolve(value);\n })\n .then(undefined, error => {\n if (settled) {\n return;\n }\n clearTimeout(timeoutId);\n settled = true;\n reject(error);\n });\n });\n}\n\nfunction isClose(t1: number, t2: number): boolean {\n return Math.abs(t1 - t2) < MARGIN_OF_ERROR_SECONDS;\n}\n"]}
|
|
@@ -26,6 +26,6 @@ export declare const stallTrackingIntegration: ({ minimumStallThresholdMs, }?: {
|
|
|
26
26
|
* How long in milliseconds an event loop iteration can be delayed for before being considered a "stall."
|
|
27
27
|
* @default 50
|
|
28
28
|
*/
|
|
29
|
-
minimumStallThresholdMs?: number
|
|
29
|
+
minimumStallThresholdMs?: number;
|
|
30
30
|
}) => Integration;
|
|
31
31
|
//# sourceMappingURL=stalltracking.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stalltracking.d.ts","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/stalltracking.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,WAAW,EAAE,YAAY,EAAE,eAAe,EAAQ,MAAM,cAAc,CAAC;AAI7F,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAMvF,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACrD,CAAC,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;IACxD,CAAC,gBAAgB,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;IAC7D,CAAC,kBAAkB,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;CAChE;AASD;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB;
|
|
1
|
+
{"version":3,"file":"stalltracking.d.ts","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/stalltracking.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,WAAW,EAAE,YAAY,EAAE,eAAe,EAAQ,MAAM,cAAc,CAAC;AAI7F,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAMvF,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACrD,CAAC,WAAW,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;IACxD,CAAC,gBAAgB,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;IAC7D,CAAC,kBAAkB,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,eAAe,CAAA;KAAE,CAAC;CAChE;AASD;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,GAAI,+BAEtC;IACD;;;OAGG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAC7B,KAAG,WA8TR,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { debug, getRootSpan, spanToJSON, timestampInSeconds } from '@sentry/core';
|
|
1
|
+
import { debug, getRootSpan, spanIsSampled, spanToJSON, timestampInSeconds } from '@sentry/core';
|
|
2
2
|
import { AppState } from 'react-native';
|
|
3
3
|
import { STALL_COUNT, STALL_LONGEST_TIME, STALL_TOTAL_TIME } from '../../measurements';
|
|
4
4
|
import { isRootSpan } from '../../utils/span';
|
|
@@ -66,6 +66,9 @@ export const stallTrackingIntegration = ({ minimumStallThresholdMs = 50, } = {})
|
|
|
66
66
|
if (!isRootSpan(rootSpan)) {
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
|
+
if (!spanIsSampled(rootSpan)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
69
72
|
if (statsByRootSpan.has(rootSpan)) {
|
|
70
73
|
debug.error('[StallTracking] Tried to start stall tracking on a transaction already being tracked. Measurements might be lost.');
|
|
71
74
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stalltracking.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/stalltracking.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Integration, Measurements, MeasurementUnit, Span } from '@sentry/core';\nimport { debug, getRootSpan, spanToJSON, timestampInSeconds } from '@sentry/core';\nimport type { AppStateStatus } from 'react-native';\nimport { AppState } from 'react-native';\nimport { STALL_COUNT, STALL_LONGEST_TIME, STALL_TOTAL_TIME } from '../../measurements';\nimport { isRootSpan } from '../../utils/span';\nimport { getLatestChildSpanEndTimestamp, isNearToNow, setSpanMeasurement } from '../utils';\n\nconst INTEGRATION_NAME = 'StallTracking';\n\nexport interface StallMeasurements extends Measurements {\n [STALL_COUNT]: { value: number; unit: MeasurementUnit };\n [STALL_TOTAL_TIME]: { value: number; unit: MeasurementUnit };\n [STALL_LONGEST_TIME]: { value: number; unit: MeasurementUnit };\n}\n\n/** Margin of error of 20ms */\nconst MARGIN_OF_ERROR_SECONDS = 0.02;\n/** How long between each iteration in the event loop tracker timeout */\nconst LOOP_TIMEOUT_INTERVAL_MS = 50;\n/** Limit for how many transactions the stall tracker will track at a time to prevent leaks due to transactions not being finished */\nconst MAX_RUNNING_TRANSACTIONS = 10;\n\n/**\n * Stall measurement tracker inspired by the `JSEventLoopWatchdog` used internally in React Native:\n * https://github.com/facebook/react-native/blob/006f5afe120c290a37cf6ff896748fbc062bf7ed/Libraries/Interaction/JSEventLoopWatchdog.js\n *\n * However, we modified the interval implementation to instead have a fixed loop timeout interval of `LOOP_TIMEOUT_INTERVAL_MS`.\n * We then would consider that iteration a stall when the total time for that interval to run is greater than `LOOP_TIMEOUT_INTERVAL_MS + minimumStallThreshold`\n */\nexport const stallTrackingIntegration = ({\n minimumStallThresholdMs = 50,\n}: {\n /**\n * How long in milliseconds an event loop iteration can be delayed for before being considered a \"stall.\"\n * @default 50\n */\n minimumStallThresholdMs?: number;\n} = {}): Integration => {\n const statsByRootSpan: Map<\n Span,\n {\n longestStallTime: number;\n atStart: StallMeasurements;\n atTimestamp: {\n timestamp: number;\n stats: StallMeasurements;\n } | null;\n }\n > = new Map();\n\n const state: {\n isTracking: boolean;\n timeout: ReturnType<typeof setTimeout> | null;\n isBackground: boolean;\n /** Switch that enables the iteration once app moves from background to foreground. */\n backgroundEventListener: (appState: AppStateStatus) => void;\n /** The last timestamp the iteration ran in milliseconds */\n lastIntervalMs: number;\n /** Total amount of time of all stalls that occurred during the current tracking session */\n totalStallTime: number;\n /** Total number of stalls that occurred during the current tracking session */\n stallCount: number;\n /**\n * Iteration of the stall tracking interval. Measures how long the timer strayed from its expected time of running, and how\n * long the stall is for.\n */\n iteration: () => void;\n } = {\n isTracking: false,\n timeout: null,\n isBackground: false,\n lastIntervalMs: 0,\n totalStallTime: 0,\n stallCount: 0,\n backgroundEventListener: (appState: AppStateStatus): void => {\n if (appState === ('active' as AppStateStatus)) {\n state.isBackground = false;\n if (state.timeout != null) {\n state.lastIntervalMs = timestampInSeconds() * 1000;\n state.iteration();\n }\n } else {\n state.isBackground = true;\n state.timeout !== null && clearTimeout(state.timeout);\n }\n },\n iteration: (): void => {\n const now = timestampInSeconds() * 1000;\n const totalTimeTaken = now - state.lastIntervalMs;\n\n if (totalTimeTaken >= LOOP_TIMEOUT_INTERVAL_MS + minimumStallThresholdMs) {\n const stallTime = totalTimeTaken - LOOP_TIMEOUT_INTERVAL_MS;\n state.stallCount += 1;\n state.totalStallTime += stallTime;\n\n for (const [transaction, value] of statsByRootSpan.entries()) {\n const longestStallTime = Math.max(value.longestStallTime ?? 0, stallTime);\n\n statsByRootSpan.set(transaction, {\n ...value,\n longestStallTime,\n });\n }\n }\n\n state.lastIntervalMs = now;\n\n if (state.isTracking && !state.isBackground) {\n state.timeout = setTimeout(state.iteration, LOOP_TIMEOUT_INTERVAL_MS);\n }\n },\n };\n\n const setup = (client: Client): void => {\n client.on('spanStart', _onSpanStart);\n client.on('spanEnd', _onSpanEnd);\n };\n\n const _onSpanStart = (rootSpan: Span): void => {\n if (!isRootSpan(rootSpan)) {\n return;\n }\n\n if (statsByRootSpan.has(rootSpan)) {\n debug.error(\n '[StallTracking] Tried to start stall tracking on a transaction already being tracked. Measurements might be lost.',\n );\n return;\n }\n\n _startTracking();\n statsByRootSpan.set(rootSpan, {\n longestStallTime: 0,\n atTimestamp: null,\n atStart: _getCurrentStats(rootSpan),\n });\n _flushLeakedTransactions();\n };\n\n const _onSpanEnd = (rootSpan: Span): void => {\n if (!isRootSpan(rootSpan)) {\n return _onChildSpanEnd(rootSpan);\n }\n\n const transactionStats = statsByRootSpan.get(rootSpan);\n\n if (!transactionStats) {\n // Transaction has been flushed out somehow, we return null.\n debug.log('[StallTracking] Stall measurements were not added to transaction due to exceeding the max count.');\n\n statsByRootSpan.delete(rootSpan);\n _shouldStopTracking();\n\n return;\n }\n\n // The endTimestamp is always set, but type-wise it's optional\n // https://github.com/getsentry/sentry-javascript/blob/38bd57b0785c97c413f36f89ff931d927e469078/packages/core/src/tracing/sentrySpan.ts#L170\n const endTimestamp = spanToJSON(rootSpan).timestamp;\n\n let statsOnFinish: StallMeasurements | undefined;\n if (isNearToNow(endTimestamp)) {\n statsOnFinish = _getCurrentStats(rootSpan);\n } else {\n // The idleSpan in JS V8 is always trimmed to the last span's endTimestamp (timestamp).\n // The unfinished child spans are removed from the root span after the `spanEnd` event.\n\n const latestChildSpanEnd = getLatestChildSpanEndTimestamp(rootSpan);\n if (latestChildSpanEnd !== endTimestamp) {\n debug.log(\n '[StallTracking] Stall measurements not added due to a custom `endTimestamp` (root end is not equal to the latest child span end).',\n );\n }\n\n if (!transactionStats.atTimestamp) {\n debug.log(\n '[StallTracking] Stall measurements not added due to `endTimestamp` not being close to now. And no previous stats from child end were found.',\n );\n }\n\n if (latestChildSpanEnd === endTimestamp && transactionStats.atTimestamp) {\n statsOnFinish = transactionStats.atTimestamp.stats;\n }\n }\n\n statsByRootSpan.delete(rootSpan);\n _shouldStopTracking();\n\n if (!statsOnFinish) {\n if (typeof endTimestamp !== 'undefined') {\n debug.log(\n '[StallTracking] Stall measurements not added due to `endTimestamp` not being close to now.',\n 'endTimestamp',\n endTimestamp,\n 'now',\n timestampInSeconds(),\n );\n }\n\n return;\n }\n\n setSpanMeasurement(\n rootSpan,\n STALL_COUNT,\n statsOnFinish.stall_count.value - transactionStats.atStart.stall_count.value,\n transactionStats.atStart.stall_count.unit,\n );\n\n setSpanMeasurement(\n rootSpan,\n STALL_TOTAL_TIME,\n statsOnFinish.stall_total_time.value - transactionStats.atStart.stall_total_time.value,\n transactionStats.atStart.stall_total_time.unit,\n );\n\n setSpanMeasurement(\n rootSpan,\n STALL_LONGEST_TIME,\n statsOnFinish.stall_longest_time.value,\n statsOnFinish.stall_longest_time.unit,\n );\n };\n\n const _onChildSpanEnd = (childSpan: Span): void => {\n const rootSpan = getRootSpan(childSpan);\n\n const finalEndTimestamp = spanToJSON(childSpan).timestamp;\n if (finalEndTimestamp) {\n _markSpanFinish(rootSpan, finalEndTimestamp);\n }\n };\n\n /**\n * Logs the finish time of the span for use in `trimEnd: true` transactions.\n */\n const _markSpanFinish = (rootSpan: Span, childSpanEndTime: number): void => {\n const previousStats = statsByRootSpan.get(rootSpan);\n if (previousStats) {\n if (Math.abs(timestampInSeconds() - childSpanEndTime) > MARGIN_OF_ERROR_SECONDS) {\n debug.log(\n '[StallTracking] Span end not logged due to end timestamp being outside the margin of error from now.',\n );\n\n if (previousStats.atTimestamp && previousStats.atTimestamp.timestamp < childSpanEndTime) {\n // We also need to delete the stat for the last span, as the transaction would be trimmed to this span not the last one.\n statsByRootSpan.set(rootSpan, {\n ...previousStats,\n atTimestamp: null,\n });\n }\n } else {\n statsByRootSpan.set(rootSpan, {\n ...previousStats,\n atTimestamp: {\n timestamp: childSpanEndTime,\n stats: _getCurrentStats(rootSpan),\n },\n });\n }\n }\n };\n\n /**\n * Get the current stats for a transaction at a given time.\n */\n const _getCurrentStats = (span: Span): StallMeasurements => {\n return {\n stall_count: { value: state.stallCount, unit: 'none' },\n stall_total_time: { value: state.totalStallTime, unit: 'millisecond' },\n stall_longest_time: {\n value: statsByRootSpan.get(span)?.longestStallTime ?? 0,\n unit: 'millisecond',\n },\n };\n };\n\n /**\n * Start tracking stalls\n */\n const _startTracking = (): void => {\n if (!state.isTracking) {\n state.isTracking = true;\n state.lastIntervalMs = Math.floor(timestampInSeconds() * 1000);\n\n state.iteration();\n }\n };\n\n /**\n * Stops the stall tracking interval and calls reset().\n */\n const _stopTracking = (): void => {\n state.isTracking = false;\n\n if (state.timeout !== null) {\n clearTimeout(state.timeout);\n state.timeout = null;\n }\n\n _reset();\n };\n\n /**\n * Will stop tracking if there are no more transactions.\n */\n const _shouldStopTracking = (): void => {\n if (statsByRootSpan.size === 0) {\n _stopTracking();\n }\n };\n\n /**\n * Clears all the collected stats\n */\n const _reset = (): void => {\n state.stallCount = 0;\n state.totalStallTime = 0;\n state.lastIntervalMs = 0;\n statsByRootSpan.clear();\n };\n\n /**\n * Deletes leaked transactions (Earliest transactions when we have more than MAX_RUNNING_TRANSACTIONS transactions.)\n */\n const _flushLeakedTransactions = (): void => {\n if (statsByRootSpan.size > MAX_RUNNING_TRANSACTIONS) {\n let counter = 0;\n const len = statsByRootSpan.size - MAX_RUNNING_TRANSACTIONS;\n const transactions = statsByRootSpan.keys();\n for (const t of transactions) {\n if (counter >= len) break;\n counter += 1;\n statsByRootSpan.delete(t);\n }\n }\n };\n\n // Avoids throwing any error if using React Native on a environment that doesn't implement AppState.\n if (AppState?.isAvailable) {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n AppState.addEventListener('change', state.backgroundEventListener);\n }\n\n return {\n name: INTEGRATION_NAME,\n setup,\n\n /** For testing only @private */\n _internalState: state,\n } as Integration;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"stalltracking.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/stalltracking.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Integration, Measurements, MeasurementUnit, Span } from '@sentry/core';\nimport { debug, getRootSpan, spanIsSampled, spanToJSON, timestampInSeconds } from '@sentry/core';\nimport type { AppStateStatus } from 'react-native';\nimport { AppState } from 'react-native';\nimport { STALL_COUNT, STALL_LONGEST_TIME, STALL_TOTAL_TIME } from '../../measurements';\nimport { isRootSpan } from '../../utils/span';\nimport { getLatestChildSpanEndTimestamp, isNearToNow, setSpanMeasurement } from '../utils';\n\nconst INTEGRATION_NAME = 'StallTracking';\n\nexport interface StallMeasurements extends Measurements {\n [STALL_COUNT]: { value: number; unit: MeasurementUnit };\n [STALL_TOTAL_TIME]: { value: number; unit: MeasurementUnit };\n [STALL_LONGEST_TIME]: { value: number; unit: MeasurementUnit };\n}\n\n/** Margin of error of 20ms */\nconst MARGIN_OF_ERROR_SECONDS = 0.02;\n/** How long between each iteration in the event loop tracker timeout */\nconst LOOP_TIMEOUT_INTERVAL_MS = 50;\n/** Limit for how many transactions the stall tracker will track at a time to prevent leaks due to transactions not being finished */\nconst MAX_RUNNING_TRANSACTIONS = 10;\n\n/**\n * Stall measurement tracker inspired by the `JSEventLoopWatchdog` used internally in React Native:\n * https://github.com/facebook/react-native/blob/006f5afe120c290a37cf6ff896748fbc062bf7ed/Libraries/Interaction/JSEventLoopWatchdog.js\n *\n * However, we modified the interval implementation to instead have a fixed loop timeout interval of `LOOP_TIMEOUT_INTERVAL_MS`.\n * We then would consider that iteration a stall when the total time for that interval to run is greater than `LOOP_TIMEOUT_INTERVAL_MS + minimumStallThreshold`\n */\nexport const stallTrackingIntegration = ({\n minimumStallThresholdMs = 50,\n}: {\n /**\n * How long in milliseconds an event loop iteration can be delayed for before being considered a \"stall.\"\n * @default 50\n */\n minimumStallThresholdMs?: number;\n} = {}): Integration => {\n const statsByRootSpan: Map<\n Span,\n {\n longestStallTime: number;\n atStart: StallMeasurements;\n atTimestamp: {\n timestamp: number;\n stats: StallMeasurements;\n } | null;\n }\n > = new Map();\n\n const state: {\n isTracking: boolean;\n timeout: ReturnType<typeof setTimeout> | null;\n isBackground: boolean;\n /** Switch that enables the iteration once app moves from background to foreground. */\n backgroundEventListener: (appState: AppStateStatus) => void;\n /** The last timestamp the iteration ran in milliseconds */\n lastIntervalMs: number;\n /** Total amount of time of all stalls that occurred during the current tracking session */\n totalStallTime: number;\n /** Total number of stalls that occurred during the current tracking session */\n stallCount: number;\n /**\n * Iteration of the stall tracking interval. Measures how long the timer strayed from its expected time of running, and how\n * long the stall is for.\n */\n iteration: () => void;\n } = {\n isTracking: false,\n timeout: null,\n isBackground: false,\n lastIntervalMs: 0,\n totalStallTime: 0,\n stallCount: 0,\n backgroundEventListener: (appState: AppStateStatus): void => {\n if (appState === ('active' as AppStateStatus)) {\n state.isBackground = false;\n if (state.timeout != null) {\n state.lastIntervalMs = timestampInSeconds() * 1000;\n state.iteration();\n }\n } else {\n state.isBackground = true;\n state.timeout !== null && clearTimeout(state.timeout);\n }\n },\n iteration: (): void => {\n const now = timestampInSeconds() * 1000;\n const totalTimeTaken = now - state.lastIntervalMs;\n\n if (totalTimeTaken >= LOOP_TIMEOUT_INTERVAL_MS + minimumStallThresholdMs) {\n const stallTime = totalTimeTaken - LOOP_TIMEOUT_INTERVAL_MS;\n state.stallCount += 1;\n state.totalStallTime += stallTime;\n\n for (const [transaction, value] of statsByRootSpan.entries()) {\n const longestStallTime = Math.max(value.longestStallTime ?? 0, stallTime);\n\n statsByRootSpan.set(transaction, {\n ...value,\n longestStallTime,\n });\n }\n }\n\n state.lastIntervalMs = now;\n\n if (state.isTracking && !state.isBackground) {\n state.timeout = setTimeout(state.iteration, LOOP_TIMEOUT_INTERVAL_MS);\n }\n },\n };\n\n const setup = (client: Client): void => {\n client.on('spanStart', _onSpanStart);\n client.on('spanEnd', _onSpanEnd);\n };\n\n const _onSpanStart = (rootSpan: Span): void => {\n if (!isRootSpan(rootSpan)) {\n return;\n }\n\n if (!spanIsSampled(rootSpan)) {\n return;\n }\n\n if (statsByRootSpan.has(rootSpan)) {\n debug.error(\n '[StallTracking] Tried to start stall tracking on a transaction already being tracked. Measurements might be lost.',\n );\n return;\n }\n\n _startTracking();\n statsByRootSpan.set(rootSpan, {\n longestStallTime: 0,\n atTimestamp: null,\n atStart: _getCurrentStats(rootSpan),\n });\n _flushLeakedTransactions();\n };\n\n const _onSpanEnd = (rootSpan: Span): void => {\n if (!isRootSpan(rootSpan)) {\n return _onChildSpanEnd(rootSpan);\n }\n\n const transactionStats = statsByRootSpan.get(rootSpan);\n\n if (!transactionStats) {\n // Transaction has been flushed out somehow, we return null.\n debug.log('[StallTracking] Stall measurements were not added to transaction due to exceeding the max count.');\n\n statsByRootSpan.delete(rootSpan);\n _shouldStopTracking();\n\n return;\n }\n\n // The endTimestamp is always set, but type-wise it's optional\n // https://github.com/getsentry/sentry-javascript/blob/38bd57b0785c97c413f36f89ff931d927e469078/packages/core/src/tracing/sentrySpan.ts#L170\n const endTimestamp = spanToJSON(rootSpan).timestamp;\n\n let statsOnFinish: StallMeasurements | undefined;\n if (isNearToNow(endTimestamp)) {\n statsOnFinish = _getCurrentStats(rootSpan);\n } else {\n // The idleSpan in JS V8 is always trimmed to the last span's endTimestamp (timestamp).\n // The unfinished child spans are removed from the root span after the `spanEnd` event.\n\n const latestChildSpanEnd = getLatestChildSpanEndTimestamp(rootSpan);\n if (latestChildSpanEnd !== endTimestamp) {\n debug.log(\n '[StallTracking] Stall measurements not added due to a custom `endTimestamp` (root end is not equal to the latest child span end).',\n );\n }\n\n if (!transactionStats.atTimestamp) {\n debug.log(\n '[StallTracking] Stall measurements not added due to `endTimestamp` not being close to now. And no previous stats from child end were found.',\n );\n }\n\n if (latestChildSpanEnd === endTimestamp && transactionStats.atTimestamp) {\n statsOnFinish = transactionStats.atTimestamp.stats;\n }\n }\n\n statsByRootSpan.delete(rootSpan);\n _shouldStopTracking();\n\n if (!statsOnFinish) {\n if (typeof endTimestamp !== 'undefined') {\n debug.log(\n '[StallTracking] Stall measurements not added due to `endTimestamp` not being close to now.',\n 'endTimestamp',\n endTimestamp,\n 'now',\n timestampInSeconds(),\n );\n }\n\n return;\n }\n\n setSpanMeasurement(\n rootSpan,\n STALL_COUNT,\n statsOnFinish.stall_count.value - transactionStats.atStart.stall_count.value,\n transactionStats.atStart.stall_count.unit,\n );\n\n setSpanMeasurement(\n rootSpan,\n STALL_TOTAL_TIME,\n statsOnFinish.stall_total_time.value - transactionStats.atStart.stall_total_time.value,\n transactionStats.atStart.stall_total_time.unit,\n );\n\n setSpanMeasurement(\n rootSpan,\n STALL_LONGEST_TIME,\n statsOnFinish.stall_longest_time.value,\n statsOnFinish.stall_longest_time.unit,\n );\n };\n\n const _onChildSpanEnd = (childSpan: Span): void => {\n const rootSpan = getRootSpan(childSpan);\n\n const finalEndTimestamp = spanToJSON(childSpan).timestamp;\n if (finalEndTimestamp) {\n _markSpanFinish(rootSpan, finalEndTimestamp);\n }\n };\n\n /**\n * Logs the finish time of the span for use in `trimEnd: true` transactions.\n */\n const _markSpanFinish = (rootSpan: Span, childSpanEndTime: number): void => {\n const previousStats = statsByRootSpan.get(rootSpan);\n if (previousStats) {\n if (Math.abs(timestampInSeconds() - childSpanEndTime) > MARGIN_OF_ERROR_SECONDS) {\n debug.log(\n '[StallTracking] Span end not logged due to end timestamp being outside the margin of error from now.',\n );\n\n if (previousStats.atTimestamp && previousStats.atTimestamp.timestamp < childSpanEndTime) {\n // We also need to delete the stat for the last span, as the transaction would be trimmed to this span not the last one.\n statsByRootSpan.set(rootSpan, {\n ...previousStats,\n atTimestamp: null,\n });\n }\n } else {\n statsByRootSpan.set(rootSpan, {\n ...previousStats,\n atTimestamp: {\n timestamp: childSpanEndTime,\n stats: _getCurrentStats(rootSpan),\n },\n });\n }\n }\n };\n\n /**\n * Get the current stats for a transaction at a given time.\n */\n const _getCurrentStats = (span: Span): StallMeasurements => {\n return {\n stall_count: { value: state.stallCount, unit: 'none' },\n stall_total_time: { value: state.totalStallTime, unit: 'millisecond' },\n stall_longest_time: {\n value: statsByRootSpan.get(span)?.longestStallTime ?? 0,\n unit: 'millisecond',\n },\n };\n };\n\n /**\n * Start tracking stalls\n */\n const _startTracking = (): void => {\n if (!state.isTracking) {\n state.isTracking = true;\n state.lastIntervalMs = Math.floor(timestampInSeconds() * 1000);\n\n state.iteration();\n }\n };\n\n /**\n * Stops the stall tracking interval and calls reset().\n */\n const _stopTracking = (): void => {\n state.isTracking = false;\n\n if (state.timeout !== null) {\n clearTimeout(state.timeout);\n state.timeout = null;\n }\n\n _reset();\n };\n\n /**\n * Will stop tracking if there are no more transactions.\n */\n const _shouldStopTracking = (): void => {\n if (statsByRootSpan.size === 0) {\n _stopTracking();\n }\n };\n\n /**\n * Clears all the collected stats\n */\n const _reset = (): void => {\n state.stallCount = 0;\n state.totalStallTime = 0;\n state.lastIntervalMs = 0;\n statsByRootSpan.clear();\n };\n\n /**\n * Deletes leaked transactions (Earliest transactions when we have more than MAX_RUNNING_TRANSACTIONS transactions.)\n */\n const _flushLeakedTransactions = (): void => {\n if (statsByRootSpan.size > MAX_RUNNING_TRANSACTIONS) {\n let counter = 0;\n const len = statsByRootSpan.size - MAX_RUNNING_TRANSACTIONS;\n const transactions = statsByRootSpan.keys();\n for (const t of transactions) {\n if (counter >= len) break;\n counter += 1;\n statsByRootSpan.delete(t);\n }\n }\n };\n\n // Avoids throwing any error if using React Native on a environment that doesn't implement AppState.\n if (AppState?.isAvailable) {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n AppState.addEventListener('change', state.backgroundEventListener);\n }\n\n return {\n name: INTEGRATION_NAME,\n setup,\n\n /** For testing only @private */\n _internalState: state,\n } as Integration;\n};\n"]}
|
|
@@ -83,12 +83,12 @@ export const timeToDisplayIntegration = () => {
|
|
|
83
83
|
}),
|
|
84
84
|
};
|
|
85
85
|
};
|
|
86
|
-
function addTimeToInitialDisplay(
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
function addTimeToInitialDisplay(_a) {
|
|
87
|
+
return __awaiter(this, arguments, void 0, function* ({ event, rootSpanId, transactionStartTimestampSeconds, enableTimeToInitialDisplayForPreloadedRoutes, }) {
|
|
88
|
+
var _b;
|
|
89
89
|
const ttidEndTimestampSeconds = yield NATIVE.popTimeToDisplayFor(`ttid-${rootSpanId}`);
|
|
90
90
|
event.spans = event.spans || [];
|
|
91
|
-
let ttidSpan = (
|
|
91
|
+
let ttidSpan = (_b = event.spans) === null || _b === void 0 ? void 0 : _b.find(span => span.op === UI_LOAD_INITIAL_DISPLAY);
|
|
92
92
|
if (ttidSpan && (ttidSpan.status === undefined || ttidSpan.status === 'ok') && !ttidEndTimestampSeconds) {
|
|
93
93
|
debug.log(`[${INTEGRATION_NAME}] Ttid span already exists and is ok.`, ttidSpan);
|
|
94
94
|
return ttidSpan;
|
|
@@ -124,12 +124,12 @@ function addTimeToInitialDisplay({ event, rootSpanId, transactionStartTimestampS
|
|
|
124
124
|
return ttidSpan;
|
|
125
125
|
});
|
|
126
126
|
}
|
|
127
|
-
function addAutomaticTimeToInitialDisplay(
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
function addAutomaticTimeToInitialDisplay(_a) {
|
|
128
|
+
return __awaiter(this, arguments, void 0, function* ({ event, rootSpanId, transactionStartTimestampSeconds, enableTimeToInitialDisplayForPreloadedRoutes, }) {
|
|
129
|
+
var _b, _c, _d, _e, _f, _g;
|
|
130
130
|
const ttidNativeTimestampSeconds = yield NATIVE.popTimeToDisplayFor(`ttid-navigation-${rootSpanId}`);
|
|
131
131
|
const ttidFallbackTimestampSeconds = yield getTimeToInitialDisplayFallback(rootSpanId);
|
|
132
|
-
const hasBeenSeen = (
|
|
132
|
+
const hasBeenSeen = (_d = (_c = (_b = event.contexts) === null || _b === void 0 ? void 0 : _b.trace) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d[SEMANTIC_ATTRIBUTE_ROUTE_HAS_BEEN_SEEN];
|
|
133
133
|
if (hasBeenSeen && !enableTimeToInitialDisplayForPreloadedRoutes) {
|
|
134
134
|
debug.log(`[${INTEGRATION_NAME}] Route has been seen and time to initial display is disabled for preloaded routes.`);
|
|
135
135
|
return undefined;
|
|
@@ -139,7 +139,7 @@ function addAutomaticTimeToInitialDisplay({ event, rootSpanId, transactionStartT
|
|
|
139
139
|
debug.log(`[${INTEGRATION_NAME}] No automatic ttid end timestamp found for span ${rootSpanId}.`);
|
|
140
140
|
return undefined;
|
|
141
141
|
}
|
|
142
|
-
const viewNames = (
|
|
142
|
+
const viewNames = (_f = (_e = event.contexts) === null || _e === void 0 ? void 0 : _e.app) === null || _f === void 0 ? void 0 : _f.view_names;
|
|
143
143
|
const screenName = Array.isArray(viewNames) ? viewNames[0] : viewNames;
|
|
144
144
|
const ttidSpan = createSpanJSON({
|
|
145
145
|
op: UI_LOAD_INITIAL_DISPLAY,
|
|
@@ -152,20 +152,20 @@ function addAutomaticTimeToInitialDisplay({ event, rootSpanId, transactionStartT
|
|
|
152
152
|
[SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,
|
|
153
153
|
},
|
|
154
154
|
});
|
|
155
|
-
event.spans = (
|
|
155
|
+
event.spans = (_g = event.spans) !== null && _g !== void 0 ? _g : [];
|
|
156
156
|
event.spans.push(ttidSpan);
|
|
157
157
|
return ttidSpan;
|
|
158
158
|
});
|
|
159
159
|
}
|
|
160
|
-
function addTimeToFullDisplay(
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
function addTimeToFullDisplay(_a) {
|
|
161
|
+
return __awaiter(this, arguments, void 0, function* ({ event, rootSpanId, transactionStartTimestampSeconds, ttidSpan, }) {
|
|
162
|
+
var _b;
|
|
163
163
|
const ttfdEndTimestampSeconds = yield NATIVE.popTimeToDisplayFor(`ttfd-${rootSpanId}`);
|
|
164
164
|
if (!ttidSpan || !ttfdEndTimestampSeconds) {
|
|
165
165
|
return undefined;
|
|
166
166
|
}
|
|
167
167
|
event.spans = event.spans || [];
|
|
168
|
-
let ttfdSpan = (
|
|
168
|
+
let ttfdSpan = (_b = event.spans) === null || _b === void 0 ? void 0 : _b.find(span => span.op === UI_LOAD_FULL_DISPLAY);
|
|
169
169
|
let ttfdAdjustedEndTimestampSeconds = ttfdEndTimestampSeconds;
|
|
170
170
|
const ttfdIsBeforeTtid = ttidSpan.timestamp && ttfdEndTimestampSeconds < ttidSpan.timestamp;
|
|
171
171
|
if (ttfdIsBeforeTtid && ttidSpan.timestamp) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeToDisplayIntegration.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/timeToDisplayIntegration.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Event, Integration, SpanJSON } from '@sentry/core';\nimport { debug } from '@sentry/core';\nimport { NATIVE } from '../../wrapper';\nimport { UI_LOAD_FULL_DISPLAY, UI_LOAD_INITIAL_DISPLAY } from '../ops';\nimport { SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY } from '../origin';\nimport { getReactNavigationIntegration } from '../reactnavigation';\nimport { SEMANTIC_ATTRIBUTE_ROUTE_HAS_BEEN_SEEN } from '../semanticAttributes';\nimport { SPAN_THREAD_NAME, SPAN_THREAD_NAME_JAVASCRIPT } from '../span';\nimport { getTimeToInitialDisplayFallback } from '../timeToDisplayFallback';\nimport { createSpanJSON } from '../utils';\n\nexport const INTEGRATION_NAME = 'TimeToDisplay';\n\nconst TIME_TO_DISPLAY_TIMEOUT_MS = 30_000;\nconst isDeadlineExceeded = (durationMs: number): boolean => durationMs > TIME_TO_DISPLAY_TIMEOUT_MS;\n\nexport const timeToDisplayIntegration = (): Integration => {\n let enableTimeToInitialDisplayForPreloadedRoutes = false;\n\n return {\n name: INTEGRATION_NAME,\n afterAllSetup(client) {\n enableTimeToInitialDisplayForPreloadedRoutes =\n getReactNavigationIntegration(client)?.options.enableTimeToInitialDisplayForPreloadedRoutes ?? false;\n },\n // eslint-disable-next-line complexity\n processEvent: async event => {\n if (event.type !== 'transaction') {\n // TimeToDisplay data is only relevant for transactions\n return event;\n }\n\n const rootSpanId = event.contexts?.trace?.span_id;\n if (!rootSpanId) {\n debug.warn(`[${INTEGRATION_NAME}] No root span id found in transaction.`);\n return event;\n }\n\n const transactionStartTimestampSeconds = event.start_timestamp;\n if (!transactionStartTimestampSeconds) {\n // This should never happen\n debug.warn(`[${INTEGRATION_NAME}] No transaction start timestamp found in transaction.`);\n return event;\n }\n\n event.spans = event.spans || [];\n event.measurements = event.measurements || {};\n\n const ttidSpan = await addTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n });\n const ttfdSpan = await addTimeToFullDisplay({ event, rootSpanId, transactionStartTimestampSeconds, ttidSpan });\n\n if (ttidSpan?.start_timestamp && ttidSpan?.timestamp) {\n event.measurements['time_to_initial_display'] = {\n value: (ttidSpan.timestamp - ttidSpan.start_timestamp) * 1000,\n unit: 'millisecond',\n };\n }\n\n if (ttfdSpan?.start_timestamp && ttfdSpan?.timestamp) {\n const durationMs = (ttfdSpan.timestamp - ttfdSpan.start_timestamp) * 1000;\n if (isDeadlineExceeded(durationMs)) {\n if (event.measurements['time_to_initial_display']) {\n event.measurements['time_to_full_display'] = event.measurements['time_to_initial_display'];\n }\n } else {\n event.measurements['time_to_full_display'] = {\n value: durationMs,\n unit: 'millisecond',\n };\n }\n }\n\n const newTransactionEndTimestampSeconds = Math.max(\n ttidSpan?.timestamp ?? -1,\n ttfdSpan?.timestamp ?? -1,\n event.timestamp ?? -1,\n );\n if (newTransactionEndTimestampSeconds !== -1) {\n event.timestamp = newTransactionEndTimestampSeconds;\n }\n\n return event;\n },\n };\n};\n\nasync function addTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n}): Promise<SpanJSON | undefined> {\n const ttidEndTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttid-${rootSpanId}`);\n\n event.spans = event.spans || [];\n\n let ttidSpan: SpanJSON | undefined = event.spans?.find(span => span.op === UI_LOAD_INITIAL_DISPLAY);\n\n if (ttidSpan && (ttidSpan.status === undefined || ttidSpan.status === 'ok') && !ttidEndTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] Ttid span already exists and is ok.`, ttidSpan);\n return ttidSpan;\n }\n\n if (!ttidEndTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] No manual ttid end timestamp found for span ${rootSpanId}.`);\n return addAutomaticTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n });\n }\n\n if (ttidSpan?.status && ttidSpan.status !== 'ok') {\n ttidSpan.status = 'ok';\n ttidSpan.timestamp = ttidEndTimestampSeconds;\n debug.log(`[${INTEGRATION_NAME}] Updated existing ttid span.`, ttidSpan);\n return ttidSpan;\n }\n\n ttidSpan = createSpanJSON({\n op: UI_LOAD_INITIAL_DISPLAY,\n description: 'Time To Initial Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttidEndTimestampSeconds,\n origin: SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n debug.log(`[${INTEGRATION_NAME}] Added ttid span to transaction.`, ttidSpan);\n event.spans.push(ttidSpan);\n return ttidSpan;\n}\n\nasync function addAutomaticTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n}): Promise<SpanJSON | undefined> {\n const ttidNativeTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttid-navigation-${rootSpanId}`);\n const ttidFallbackTimestampSeconds = await getTimeToInitialDisplayFallback(rootSpanId);\n\n const hasBeenSeen = event.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_ROUTE_HAS_BEEN_SEEN];\n if (hasBeenSeen && !enableTimeToInitialDisplayForPreloadedRoutes) {\n debug.log(\n `[${INTEGRATION_NAME}] Route has been seen and time to initial display is disabled for preloaded routes.`,\n );\n return undefined;\n }\n\n const ttidTimestampSeconds = ttidNativeTimestampSeconds ?? ttidFallbackTimestampSeconds;\n if (!ttidTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] No automatic ttid end timestamp found for span ${rootSpanId}.`);\n return undefined;\n }\n\n const viewNames = event.contexts?.app?.view_names;\n const screenName = Array.isArray(viewNames) ? viewNames[0] : viewNames;\n\n const ttidSpan = createSpanJSON({\n op: UI_LOAD_INITIAL_DISPLAY,\n description: screenName ? `${screenName} initial display` : 'Time To Initial Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttidTimestampSeconds,\n origin: SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n event.spans = event.spans ?? [];\n event.spans.push(ttidSpan);\n return ttidSpan;\n}\n\nasync function addTimeToFullDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n ttidSpan,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n ttidSpan: SpanJSON | undefined;\n}): Promise<SpanJSON | undefined> {\n const ttfdEndTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttfd-${rootSpanId}`);\n\n if (!ttidSpan || !ttfdEndTimestampSeconds) {\n return undefined;\n }\n\n event.spans = event.spans || [];\n\n let ttfdSpan = event.spans?.find(span => span.op === UI_LOAD_FULL_DISPLAY);\n\n let ttfdAdjustedEndTimestampSeconds = ttfdEndTimestampSeconds;\n const ttfdIsBeforeTtid = ttidSpan.timestamp && ttfdEndTimestampSeconds < ttidSpan.timestamp;\n if (ttfdIsBeforeTtid && ttidSpan.timestamp) {\n ttfdAdjustedEndTimestampSeconds = ttidSpan.timestamp;\n }\n\n const durationMs = (ttfdAdjustedEndTimestampSeconds - transactionStartTimestampSeconds) * 1000;\n\n if (ttfdSpan?.status && ttfdSpan.status !== 'ok') {\n ttfdSpan.status = 'ok';\n ttfdSpan.timestamp = ttfdAdjustedEndTimestampSeconds;\n debug.log(`[${INTEGRATION_NAME}] Updated existing ttfd span.`, ttfdSpan);\n return ttfdSpan;\n }\n\n ttfdSpan = createSpanJSON({\n status: isDeadlineExceeded(durationMs) ? 'deadline_exceeded' : 'ok',\n op: UI_LOAD_FULL_DISPLAY,\n description: 'Time To Full Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttfdAdjustedEndTimestampSeconds,\n origin: SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n debug.log(`[${INTEGRATION_NAME}] Added ttfd span to transaction.`, ttfdSpan);\n event.spans.push(ttfdSpan);\n return ttfdSpan;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"timeToDisplayIntegration.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/timeToDisplayIntegration.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Event, Integration, SpanJSON } from '@sentry/core';\nimport { debug } from '@sentry/core';\nimport { NATIVE } from '../../wrapper';\nimport { UI_LOAD_FULL_DISPLAY, UI_LOAD_INITIAL_DISPLAY } from '../ops';\nimport { SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY } from '../origin';\nimport { getReactNavigationIntegration } from '../reactnavigation';\nimport { SEMANTIC_ATTRIBUTE_ROUTE_HAS_BEEN_SEEN } from '../semanticAttributes';\nimport { SPAN_THREAD_NAME, SPAN_THREAD_NAME_JAVASCRIPT } from '../span';\nimport { getTimeToInitialDisplayFallback } from '../timeToDisplayFallback';\nimport { createSpanJSON } from '../utils';\n\nexport const INTEGRATION_NAME = 'TimeToDisplay';\n\nconst TIME_TO_DISPLAY_TIMEOUT_MS = 30_000;\nconst isDeadlineExceeded = (durationMs: number): boolean => durationMs > TIME_TO_DISPLAY_TIMEOUT_MS;\n\nexport const timeToDisplayIntegration = (): Integration => {\n let enableTimeToInitialDisplayForPreloadedRoutes = false;\n\n return {\n name: INTEGRATION_NAME,\n afterAllSetup(client) {\n enableTimeToInitialDisplayForPreloadedRoutes =\n getReactNavigationIntegration(client)?.options.enableTimeToInitialDisplayForPreloadedRoutes ?? false;\n },\n // eslint-disable-next-line complexity\n processEvent: async event => {\n if (event.type !== 'transaction') {\n // TimeToDisplay data is only relevant for transactions\n return event;\n }\n\n const rootSpanId = event.contexts?.trace?.span_id;\n if (!rootSpanId) {\n debug.warn(`[${INTEGRATION_NAME}] No root span id found in transaction.`);\n return event;\n }\n\n const transactionStartTimestampSeconds = event.start_timestamp;\n if (!transactionStartTimestampSeconds) {\n // This should never happen\n debug.warn(`[${INTEGRATION_NAME}] No transaction start timestamp found in transaction.`);\n return event;\n }\n\n event.spans = event.spans || [];\n event.measurements = event.measurements || {};\n\n const ttidSpan = await addTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n });\n const ttfdSpan = await addTimeToFullDisplay({ event, rootSpanId, transactionStartTimestampSeconds, ttidSpan });\n\n if (ttidSpan?.start_timestamp && ttidSpan?.timestamp) {\n event.measurements['time_to_initial_display'] = {\n value: (ttidSpan.timestamp - ttidSpan.start_timestamp) * 1000,\n unit: 'millisecond',\n };\n }\n\n if (ttfdSpan?.start_timestamp && ttfdSpan?.timestamp) {\n const durationMs = (ttfdSpan.timestamp - ttfdSpan.start_timestamp) * 1000;\n if (isDeadlineExceeded(durationMs)) {\n if (event.measurements['time_to_initial_display']) {\n event.measurements['time_to_full_display'] = event.measurements['time_to_initial_display'];\n }\n } else {\n event.measurements['time_to_full_display'] = {\n value: durationMs,\n unit: 'millisecond',\n };\n }\n }\n\n const newTransactionEndTimestampSeconds = Math.max(\n ttidSpan?.timestamp ?? -1,\n ttfdSpan?.timestamp ?? -1,\n event.timestamp ?? -1,\n );\n if (newTransactionEndTimestampSeconds !== -1) {\n event.timestamp = newTransactionEndTimestampSeconds;\n }\n\n return event;\n },\n };\n};\n\nasync function addTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n}): Promise<SpanJSON | undefined> {\n const ttidEndTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttid-${rootSpanId}`);\n\n event.spans = event.spans || [];\n\n let ttidSpan: SpanJSON | undefined = event.spans?.find(span => span.op === UI_LOAD_INITIAL_DISPLAY);\n\n if (ttidSpan && (ttidSpan.status === undefined || ttidSpan.status === 'ok') && !ttidEndTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] Ttid span already exists and is ok.`, ttidSpan);\n return ttidSpan;\n }\n\n if (!ttidEndTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] No manual ttid end timestamp found for span ${rootSpanId}.`);\n return addAutomaticTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n });\n }\n\n if (ttidSpan?.status && ttidSpan.status !== 'ok') {\n ttidSpan.status = 'ok';\n ttidSpan.timestamp = ttidEndTimestampSeconds;\n debug.log(`[${INTEGRATION_NAME}] Updated existing ttid span.`, ttidSpan);\n return ttidSpan;\n }\n\n ttidSpan = createSpanJSON({\n op: UI_LOAD_INITIAL_DISPLAY,\n description: 'Time To Initial Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttidEndTimestampSeconds,\n origin: SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n debug.log(`[${INTEGRATION_NAME}] Added ttid span to transaction.`, ttidSpan);\n event.spans.push(ttidSpan);\n return ttidSpan;\n}\n\nasync function addAutomaticTimeToInitialDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n enableTimeToInitialDisplayForPreloadedRoutes,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n}): Promise<SpanJSON | undefined> {\n const ttidNativeTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttid-navigation-${rootSpanId}`);\n const ttidFallbackTimestampSeconds = await getTimeToInitialDisplayFallback(rootSpanId);\n\n const hasBeenSeen = event.contexts?.trace?.data?.[SEMANTIC_ATTRIBUTE_ROUTE_HAS_BEEN_SEEN];\n if (hasBeenSeen && !enableTimeToInitialDisplayForPreloadedRoutes) {\n debug.log(\n `[${INTEGRATION_NAME}] Route has been seen and time to initial display is disabled for preloaded routes.`,\n );\n return undefined;\n }\n\n const ttidTimestampSeconds = ttidNativeTimestampSeconds ?? ttidFallbackTimestampSeconds;\n if (!ttidTimestampSeconds) {\n debug.log(`[${INTEGRATION_NAME}] No automatic ttid end timestamp found for span ${rootSpanId}.`);\n return undefined;\n }\n\n const viewNames = event.contexts?.app?.view_names;\n const screenName = Array.isArray(viewNames) ? viewNames[0] : viewNames;\n\n const ttidSpan = createSpanJSON({\n op: UI_LOAD_INITIAL_DISPLAY,\n description: screenName ? `${screenName} initial display` : 'Time To Initial Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttidTimestampSeconds,\n origin: SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n event.spans = event.spans ?? [];\n event.spans.push(ttidSpan);\n return ttidSpan;\n}\n\nasync function addTimeToFullDisplay({\n event,\n rootSpanId,\n transactionStartTimestampSeconds,\n ttidSpan,\n}: {\n event: Event;\n rootSpanId: string;\n transactionStartTimestampSeconds: number;\n ttidSpan: SpanJSON | undefined;\n}): Promise<SpanJSON | undefined> {\n const ttfdEndTimestampSeconds = await NATIVE.popTimeToDisplayFor(`ttfd-${rootSpanId}`);\n\n if (!ttidSpan || !ttfdEndTimestampSeconds) {\n return undefined;\n }\n\n event.spans = event.spans || [];\n\n let ttfdSpan = event.spans?.find(span => span.op === UI_LOAD_FULL_DISPLAY);\n\n let ttfdAdjustedEndTimestampSeconds = ttfdEndTimestampSeconds;\n const ttfdIsBeforeTtid = ttidSpan.timestamp && ttfdEndTimestampSeconds < ttidSpan.timestamp;\n if (ttfdIsBeforeTtid && ttidSpan.timestamp) {\n ttfdAdjustedEndTimestampSeconds = ttidSpan.timestamp;\n }\n\n const durationMs = (ttfdAdjustedEndTimestampSeconds - transactionStartTimestampSeconds) * 1000;\n\n if (ttfdSpan?.status && ttfdSpan.status !== 'ok') {\n ttfdSpan.status = 'ok';\n ttfdSpan.timestamp = ttfdAdjustedEndTimestampSeconds;\n debug.log(`[${INTEGRATION_NAME}] Updated existing ttfd span.`, ttfdSpan);\n return ttfdSpan;\n }\n\n ttfdSpan = createSpanJSON({\n status: isDeadlineExceeded(durationMs) ? 'deadline_exceeded' : 'ok',\n op: UI_LOAD_FULL_DISPLAY,\n description: 'Time To Full Display',\n start_timestamp: transactionStartTimestampSeconds,\n timestamp: ttfdAdjustedEndTimestampSeconds,\n origin: SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY,\n parent_span_id: rootSpanId,\n data: {\n [SPAN_THREAD_NAME]: SPAN_THREAD_NAME_JAVASCRIPT,\n },\n });\n debug.log(`[${INTEGRATION_NAME}] Added ttfd span to transaction.`, ttfdSpan);\n event.spans.push(ttfdSpan);\n return ttfdSpan;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"userInteraction.d.ts","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/userInteraction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAoB,MAAM,cAAc,CAAC;AAiBxE,eAAO,MAAM,0BAA0B,QAAO,WAI7C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,
|
|
1
|
+
{"version":3,"file":"userInteraction.d.ts","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/userInteraction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,IAAI,EAAoB,MAAM,cAAc,CAAC;AAiBxE,eAAO,MAAM,0BAA0B,QAAO,WAI7C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GAAI,mBAAmB;IAC1D,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,EAAE,EAAE,MAAM,CAAC;CACZ,KAAG,IAAI,GAAG,SAmEV,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"userInteraction.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/userInteraction.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EACL,aAAa,EACb,SAAS,EACT,eAAe,EACf,gCAAgC,EAChC,UAAU,GACX,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,8BAA8B,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,uCAAuC,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE3F,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAE3C,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAgB,EAAE;IAC1D,OAAO;QACL,IAAI,EAAE,gBAAgB;KACvB,CAAC;AACJ,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,iBAGxC,EAAoB,EAAE;IACrB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,IAAI,CAAC,MAAM,EAAE;
|
|
1
|
+
{"version":3,"file":"userInteraction.js","sourceRoot":"","sources":["../../../../src/js/tracing/integrations/userInteraction.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Integration, Span, StartSpanOptions } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getClient,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport type { ReactNativeClientOptions } from '../../options';\nimport { onlySampleIfChildSpans } from '../onSpanEndUtils';\nimport { SPAN_ORIGIN_MANUAL_INTERACTION } from '../origin';\nimport { getCurrentReactNativeTracingIntegration } from '../reactnativetracing';\nimport { clearActiveSpanFromScope, isSentryInteractionSpan, startIdleSpan } from '../span';\n\nconst INTEGRATION_NAME = 'UserInteraction';\n\nexport const userInteractionIntegration = (): Integration => {\n return {\n name: INTEGRATION_NAME,\n };\n};\n\n/**\n * Starts a new transaction for a user interaction.\n * @param userInteractionId Consists of `op` representation UI Event and `elementId` unique element identifier on current screen.\n */\nexport const startUserInteractionSpan = (userInteractionId: {\n elementId: string | undefined;\n op: string;\n}): Span | undefined => {\n const client = getClient();\n if (!client) {\n return undefined;\n }\n\n const tracing = getCurrentReactNativeTracingIntegration();\n if (!tracing) {\n debug.log(`[${INTEGRATION_NAME}] Tracing integration is not available. Can not start user interaction span.`);\n return undefined;\n }\n\n const options = client.getOptions() as ReactNativeClientOptions;\n const { elementId, op } = userInteractionId;\n if (!options.enableUserInteractionTracing) {\n debug.log(`[${INTEGRATION_NAME}] User Interaction Tracing is disabled.`);\n return undefined;\n }\n if (!elementId) {\n debug.log(`[${INTEGRATION_NAME}] User Interaction Tracing can not create transaction with undefined elementId.`);\n return undefined;\n }\n if (!tracing.state.currentRoute) {\n debug.log(`[${INTEGRATION_NAME}] User Interaction Tracing can not create transaction without a current route.`);\n return undefined;\n }\n\n const activeTransaction = getActiveSpan();\n const activeTransactionIsNotInteraction = activeTransaction && !isSentryInteractionSpan(activeTransaction);\n if (activeTransaction && activeTransactionIsNotInteraction) {\n debug.warn(\n `[${INTEGRATION_NAME}] Did not create ${op} transaction because active transaction ${\n spanToJSON(activeTransaction).description\n } exists on the scope.`,\n );\n return undefined;\n }\n\n const name = `${tracing.state.currentRoute}.${elementId}`;\n if (\n activeTransaction &&\n spanToJSON(activeTransaction).description === name &&\n spanToJSON(activeTransaction).op === op\n ) {\n debug.warn(\n `[${INTEGRATION_NAME}] Did not create ${op} transaction because it the same transaction ${\n spanToJSON(activeTransaction).description\n } already exists on the scope.`,\n );\n return undefined;\n }\n\n const scope = getCurrentScope();\n const context: StartSpanOptions = {\n name,\n op,\n scope,\n };\n clearActiveSpanFromScope(scope);\n const newSpan = startIdleSpan(context, {\n idleTimeout: tracing.options.idleTimeoutMs,\n finalTimeout: tracing.options.finalTimeoutMs,\n });\n newSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_MANUAL_INTERACTION);\n onlySampleIfChildSpans(client, newSpan);\n debug.log(`[${INTEGRATION_NAME}] User Interaction Tracing Created ${op} transaction ${name}.`);\n return newSpan;\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onSpanEndUtils.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/onSpanEndUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAYjD;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"onSpanEndUtils.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/onSpanEndUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAYjD;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,GAAG,IAAI,CAQ9F;AAED,eAAO,MAAM,yBAAyB,GAAI,QAAQ,MAAM,EAAE,MAAM,IAAI,EAAE,eAAe,MAAM,KAAG,IA2B7F,CAAC;AAyDF,eAAO,MAAM,yBAAyB,GAAI,QAAQ,MAAM,GAAG,SAAS,EAAE,MAAM,IAAI,GAAG,SAAS,KAAG,IAa9F,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,kCAAkC,GAC7C,QAAQ,MAAM,GAAG,SAAS,EAC1B,MAAM,IAAI,GAAG,SAAS,EACtB,2BAA2B,MAAM,EACjC,oBAAoB,MAAM,OAAO,KAChC,IAoBF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GAAI,QAAQ,MAAM,EAAE,MAAM,IAAI,KAAG,IAoBnE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,EAAE,MAAM,IAAI,KAAG,IA8C/D,CAAC"}
|
|
@@ -10,10 +10,11 @@ const IOS_INACTIVE_CANCEL_DELAY_MS = 5000;
|
|
|
10
10
|
* Hooks on span end event to execute a callback when the span ends.
|
|
11
11
|
*/
|
|
12
12
|
export function onThisSpanEnd(client, span, callback) {
|
|
13
|
-
client.on('spanEnd', (endedSpan) => {
|
|
13
|
+
const unsubscribe = client.on('spanEnd', (endedSpan) => {
|
|
14
14
|
if (span !== endedSpan) {
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
|
+
unsubscribe();
|
|
17
18
|
callback(endedSpan);
|
|
18
19
|
});
|
|
19
20
|
}
|
|
@@ -22,10 +23,11 @@ export const adjustTransactionDuration = (client, span, maxDurationMs) => {
|
|
|
22
23
|
debug.warn('Not sampling empty back spans only works for Sentry Transactions (Root Spans).');
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
25
|
-
client.on('spanEnd', (endedSpan) => {
|
|
26
|
+
const unsubscribe = client.on('spanEnd', (endedSpan) => {
|
|
26
27
|
if (endedSpan !== span) {
|
|
27
28
|
return;
|
|
28
29
|
}
|
|
30
|
+
unsubscribe();
|
|
29
31
|
const endTimestamp = spanToJSON(span).timestamp;
|
|
30
32
|
const startTimestamp = spanToJSON(span).start_timestamp;
|
|
31
33
|
if (!endTimestamp || !startTimestamp) {
|
|
@@ -65,10 +67,11 @@ function discardEmptyNavigationSpan(client, span, shouldDiscardFn, onDiscardFn)
|
|
|
65
67
|
debug.warn('Not sampling empty navigation spans only works for Sentry Transactions (Root Spans).');
|
|
66
68
|
return;
|
|
67
69
|
}
|
|
68
|
-
client.on('spanEnd', (endedSpan) => {
|
|
70
|
+
const unsubscribe = client.on('spanEnd', (endedSpan) => {
|
|
69
71
|
if (endedSpan !== span) {
|
|
70
72
|
return;
|
|
71
73
|
}
|
|
74
|
+
unsubscribe();
|
|
72
75
|
if (!shouldDiscardFn(span)) {
|
|
73
76
|
return;
|
|
74
77
|
}
|
|
@@ -122,10 +125,11 @@ export const onlySampleIfChildSpans = (client, span) => {
|
|
|
122
125
|
debug.warn('Not sampling childless spans only works for Sentry Transactions (Root Spans).');
|
|
123
126
|
return;
|
|
124
127
|
}
|
|
125
|
-
client.on('spanEnd', (endedSpan) => {
|
|
128
|
+
const unsubscribe = client.on('spanEnd', (endedSpan) => {
|
|
126
129
|
if (endedSpan !== span) {
|
|
127
130
|
return;
|
|
128
131
|
}
|
|
132
|
+
unsubscribe();
|
|
129
133
|
const children = getSpanDescendants(span);
|
|
130
134
|
if (children.length <= 1) {
|
|
131
135
|
// Span always has at lest one child, itself
|
|
@@ -175,17 +179,20 @@ export const cancelInBackground = (client, span) => {
|
|
|
175
179
|
}
|
|
176
180
|
}
|
|
177
181
|
});
|
|
178
|
-
subscription
|
|
179
|
-
client.on('spanEnd', (endedSpan) => {
|
|
182
|
+
if (subscription) {
|
|
183
|
+
const unsubscribe = client.on('spanEnd', (endedSpan) => {
|
|
180
184
|
var _a;
|
|
181
|
-
if (endedSpan
|
|
182
|
-
|
|
183
|
-
if (inactiveTimeout !== undefined) {
|
|
184
|
-
clearTimeout(inactiveTimeout);
|
|
185
|
-
inactiveTimeout = undefined;
|
|
186
|
-
}
|
|
187
|
-
(_a = subscription === null || subscription === void 0 ? void 0 : subscription.remove) === null || _a === void 0 ? void 0 : _a.call(subscription);
|
|
185
|
+
if (endedSpan !== span) {
|
|
186
|
+
return;
|
|
188
187
|
}
|
|
188
|
+
unsubscribe();
|
|
189
|
+
debug.log(`Removing AppState listener for ${spanToJSON(span).op} transaction.`);
|
|
190
|
+
if (inactiveTimeout !== undefined) {
|
|
191
|
+
clearTimeout(inactiveTimeout);
|
|
192
|
+
inactiveTimeout = undefined;
|
|
193
|
+
}
|
|
194
|
+
(_a = subscription.remove) === null || _a === void 0 ? void 0 : _a.call(subscription);
|
|
189
195
|
});
|
|
196
|
+
}
|
|
190
197
|
};
|
|
191
198
|
//# sourceMappingURL=onSpanEndUtils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onSpanEndUtils.js","sourceRoot":"","sources":["../../../src/js/tracing/onSpanEndUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Client, Span } from '@sentry/core';\nimport { debug, getSpanDescendants, SPAN_STATUS_ERROR, spanToJSON } from '@sentry/core';\nimport type { AppStateStatus } from 'react-native';\nimport { AppState, Platform } from 'react-native';\nimport { isRootSpan, isSentrySpan } from '../utils/span';\n\n/**\n * The time to wait after the app enters the `inactive` state on iOS before\n * cancelling the span.\n */\nconst IOS_INACTIVE_CANCEL_DELAY_MS = 5_000;\n\n/**\n * Hooks on span end event to execute a callback when the span ends.\n */\nexport function onThisSpanEnd(client: Client, span: Span, callback: (span: Span) => void): void {\n client.on('spanEnd', (endedSpan: Span) => {\n if (span !== endedSpan) {\n return;\n }\n callback(endedSpan);\n });\n}\n\nexport const adjustTransactionDuration = (client: Client, span: Span, maxDurationMs: number): void => {\n if (!isRootSpan(span)) {\n debug.warn('Not sampling empty back spans only works for Sentry Transactions (Root Spans).');\n return;\n }\n\n client.on('spanEnd', (endedSpan: Span) => {\n if (endedSpan !== span) {\n return;\n }\n\n const endTimestamp = spanToJSON(span).timestamp;\n const startTimestamp = spanToJSON(span).start_timestamp;\n if (!endTimestamp || !startTimestamp) {\n return;\n }\n\n const diff = endTimestamp - startTimestamp; // a diff in *seconds*\n const isOutdatedTransaction = diff > maxDurationMs / 1000 || diff < 0;\n\n if (isOutdatedTransaction) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'deadline_exceeded' });\n // TODO: check where was used, might be possible to delete\n span.setAttribute('maxTransactionDurationExceeded', 'true');\n }\n });\n};\n\n/**\n * Helper function to filter out auto-instrumentation child spans.\n */\nfunction getMeaningfulChildSpans(span: Span): Span[] {\n const children = getSpanDescendants(span);\n return children.filter(\n child =>\n child.spanContext().spanId !== span.spanContext().spanId &&\n spanToJSON(child).op !== 'ui.load.initial_display' &&\n spanToJSON(child).op !== 'navigation.processing',\n );\n}\n\n/**\n * Generic helper to discard empty navigation spans based on a condition.\n */\nfunction discardEmptyNavigationSpan(\n client: Client | undefined,\n span: Span | undefined,\n shouldDiscardFn: (span: Span) => boolean,\n onDiscardFn: (span: Span) => void,\n): void {\n if (!client) {\n debug.warn('Could not hook on spanEnd event because client is not defined.');\n return;\n }\n\n if (!span) {\n debug.warn('Could not hook on spanEnd event because span is not defined.');\n return;\n }\n\n if (!isRootSpan(span) || !isSentrySpan(span)) {\n debug.warn('Not sampling empty navigation spans only works for Sentry Transactions (Root Spans).');\n return;\n }\n\n client.on('spanEnd', (endedSpan: Span) => {\n if (endedSpan !== span) {\n return;\n }\n\n if (!shouldDiscardFn(span)) {\n return;\n }\n\n const meaningfulChildren = getMeaningfulChildSpans(span);\n if (meaningfulChildren.length <= 0) {\n onDiscardFn(span);\n span['_sampled'] = false;\n }\n });\n}\n\nexport const ignoreEmptyBackNavigation = (client: Client | undefined, span: Span | undefined): void => {\n discardEmptyNavigationSpan(\n client,\n span,\n // Only discard if route has been seen before\n span => spanToJSON(span).data?.['route.has_been_seen'] === true,\n // Log message when discarding\n () => {\n debug.log(\n 'Not sampling transaction as route has been seen before. Pass ignoreEmptyBackNavigationTransactions = false to disable this feature.',\n );\n },\n );\n};\n\n/**\n * Discards empty \"Route Change\" transactions that never received route information.\n * This happens when navigation library emits a route change event but getCurrentRoute() returns undefined.\n * Such transactions don't contain any useful information and should not be sent to Sentry.\n *\n * This function must be called with a reference tracker function that can check if the span\n * was cleared from the integration's tracking (indicating it went through the state listener).\n */\nexport const ignoreEmptyRouteChangeTransactions = (\n client: Client | undefined,\n span: Span | undefined,\n defaultNavigationSpanName: string,\n isSpanStillTracked: () => boolean,\n): void => {\n discardEmptyNavigationSpan(\n client,\n span,\n // Only discard if:\n // 1. Still has default name\n // 2. No route information was set\n // 3. Still being tracked (state listener never called)\n span => {\n const spanJSON = spanToJSON(span);\n return (\n spanJSON.description === defaultNavigationSpanName && !spanJSON.data?.['route.name'] && isSpanStillTracked()\n );\n },\n // Log and record dropped event\n _span => {\n debug.log(`Discarding empty \"${defaultNavigationSpanName}\" transaction that never received route information.`);\n client?.recordDroppedEvent('sample_rate', 'transaction');\n },\n );\n};\n\n/**\n * Idle Transaction callback to only sample transactions with child spans.\n * To avoid side effects of other callbacks this should be hooked as the last callback.\n */\nexport const onlySampleIfChildSpans = (client: Client, span: Span): void => {\n if (!isRootSpan(span) || !isSentrySpan(span)) {\n debug.warn('Not sampling childless spans only works for Sentry Transactions (Root Spans).');\n return;\n }\n\n client.on('spanEnd', (endedSpan: Span) => {\n if (endedSpan !== span) {\n return;\n }\n\n const children = getSpanDescendants(span);\n\n if (children.length <= 1) {\n // Span always has at lest one child, itself\n debug.log(`Not sampling as ${spanToJSON(span).op} transaction has no child spans.`);\n span['_sampled'] = false;\n }\n });\n};\n\n/**\n * Hooks on AppState change to cancel the span if the app goes background.\n *\n * On iOS the JS thread can be suspended between the `inactive` and\n * `background` transitions, which means the `background` event may never\n * reach JS in time. To handle this we schedule a deferred cancellation when\n * the app becomes `inactive`. If the app returns to `active` before the\n * timeout fires, the cancellation is cleared. If it transitions to\n * `background` first, we cancel immediately and clear the timeout.\n */\nexport const cancelInBackground = (client: Client, span: Span): void => {\n let inactiveTimeout: ReturnType<typeof setTimeout> | undefined;\n\n const cancelSpan = (): void => {\n if (inactiveTimeout !== undefined) {\n clearTimeout(inactiveTimeout);\n inactiveTimeout = undefined;\n }\n debug.log(`Setting ${spanToJSON(span).op} transaction to cancelled because the app is in the background.`);\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'cancelled' });\n span.end();\n };\n\n const subscription = AppState.addEventListener('change', (newState: AppStateStatus) => {\n if (newState === 'background') {\n cancelSpan();\n } else if (Platform.OS === 'ios' && newState === 'inactive') {\n // Schedule a deferred cancellation — if the JS thread is suspended\n // before the 'background' event fires, this timer will execute when\n // the app is eventually resumed and end the span.\n if (inactiveTimeout === undefined) {\n inactiveTimeout = setTimeout(cancelSpan, IOS_INACTIVE_CANCEL_DELAY_MS);\n }\n } else if (newState === 'active') {\n // App returned to foreground — clear any pending inactive cancellation.\n if (inactiveTimeout !== undefined) {\n clearTimeout(inactiveTimeout);\n inactiveTimeout = undefined;\n }\n }\n });\n\n subscription &&\n client.on('spanEnd', (endedSpan: Span) => {\n if (endedSpan === span) {\n debug.log(`Removing AppState listener for ${spanToJSON(span).op} transaction.`);\n if (inactiveTimeout !== undefined) {\n clearTimeout(inactiveTimeout);\n inactiveTimeout = undefined;\n }\n subscription?.remove?.();\n }\n });\n};\n"]}
|
|
1
|
+
{"version":3,"file":"onSpanEndUtils.js","sourceRoot":"","sources":["../../../src/js/tracing/onSpanEndUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Client, Span } from '@sentry/core';\nimport { debug, getSpanDescendants, SPAN_STATUS_ERROR, spanToJSON } from '@sentry/core';\nimport type { AppStateStatus } from 'react-native';\nimport { AppState, Platform } from 'react-native';\nimport { isRootSpan, isSentrySpan } from '../utils/span';\n\n/**\n * The time to wait after the app enters the `inactive` state on iOS before\n * cancelling the span.\n */\nconst IOS_INACTIVE_CANCEL_DELAY_MS = 5_000;\n\n/**\n * Hooks on span end event to execute a callback when the span ends.\n */\nexport function onThisSpanEnd(client: Client, span: Span, callback: (span: Span) => void): void {\n const unsubscribe = client.on('spanEnd', (endedSpan: Span) => {\n if (span !== endedSpan) {\n return;\n }\n unsubscribe();\n callback(endedSpan);\n });\n}\n\nexport const adjustTransactionDuration = (client: Client, span: Span, maxDurationMs: number): void => {\n if (!isRootSpan(span)) {\n debug.warn('Not sampling empty back spans only works for Sentry Transactions (Root Spans).');\n return;\n }\n\n const unsubscribe = client.on('spanEnd', (endedSpan: Span) => {\n if (endedSpan !== span) {\n return;\n }\n unsubscribe();\n\n const endTimestamp = spanToJSON(span).timestamp;\n const startTimestamp = spanToJSON(span).start_timestamp;\n if (!endTimestamp || !startTimestamp) {\n return;\n }\n\n const diff = endTimestamp - startTimestamp; // a diff in *seconds*\n const isOutdatedTransaction = diff > maxDurationMs / 1000 || diff < 0;\n\n if (isOutdatedTransaction) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'deadline_exceeded' });\n // TODO: check where was used, might be possible to delete\n span.setAttribute('maxTransactionDurationExceeded', 'true');\n }\n });\n};\n\n/**\n * Helper function to filter out auto-instrumentation child spans.\n */\nfunction getMeaningfulChildSpans(span: Span): Span[] {\n const children = getSpanDescendants(span);\n return children.filter(\n child =>\n child.spanContext().spanId !== span.spanContext().spanId &&\n spanToJSON(child).op !== 'ui.load.initial_display' &&\n spanToJSON(child).op !== 'navigation.processing',\n );\n}\n\n/**\n * Generic helper to discard empty navigation spans based on a condition.\n */\nfunction discardEmptyNavigationSpan(\n client: Client | undefined,\n span: Span | undefined,\n shouldDiscardFn: (span: Span) => boolean,\n onDiscardFn: (span: Span) => void,\n): void {\n if (!client) {\n debug.warn('Could not hook on spanEnd event because client is not defined.');\n return;\n }\n\n if (!span) {\n debug.warn('Could not hook on spanEnd event because span is not defined.');\n return;\n }\n\n if (!isRootSpan(span) || !isSentrySpan(span)) {\n debug.warn('Not sampling empty navigation spans only works for Sentry Transactions (Root Spans).');\n return;\n }\n\n const unsubscribe = client.on('spanEnd', (endedSpan: Span) => {\n if (endedSpan !== span) {\n return;\n }\n unsubscribe();\n\n if (!shouldDiscardFn(span)) {\n return;\n }\n\n const meaningfulChildren = getMeaningfulChildSpans(span);\n if (meaningfulChildren.length <= 0) {\n onDiscardFn(span);\n span['_sampled'] = false;\n }\n });\n}\n\nexport const ignoreEmptyBackNavigation = (client: Client | undefined, span: Span | undefined): void => {\n discardEmptyNavigationSpan(\n client,\n span,\n // Only discard if route has been seen before\n span => spanToJSON(span).data?.['route.has_been_seen'] === true,\n // Log message when discarding\n () => {\n debug.log(\n 'Not sampling transaction as route has been seen before. Pass ignoreEmptyBackNavigationTransactions = false to disable this feature.',\n );\n },\n );\n};\n\n/**\n * Discards empty \"Route Change\" transactions that never received route information.\n * This happens when navigation library emits a route change event but getCurrentRoute() returns undefined.\n * Such transactions don't contain any useful information and should not be sent to Sentry.\n *\n * This function must be called with a reference tracker function that can check if the span\n * was cleared from the integration's tracking (indicating it went through the state listener).\n */\nexport const ignoreEmptyRouteChangeTransactions = (\n client: Client | undefined,\n span: Span | undefined,\n defaultNavigationSpanName: string,\n isSpanStillTracked: () => boolean,\n): void => {\n discardEmptyNavigationSpan(\n client,\n span,\n // Only discard if:\n // 1. Still has default name\n // 2. No route information was set\n // 3. Still being tracked (state listener never called)\n span => {\n const spanJSON = spanToJSON(span);\n return (\n spanJSON.description === defaultNavigationSpanName && !spanJSON.data?.['route.name'] && isSpanStillTracked()\n );\n },\n // Log and record dropped event\n _span => {\n debug.log(`Discarding empty \"${defaultNavigationSpanName}\" transaction that never received route information.`);\n client?.recordDroppedEvent('sample_rate', 'transaction');\n },\n );\n};\n\n/**\n * Idle Transaction callback to only sample transactions with child spans.\n * To avoid side effects of other callbacks this should be hooked as the last callback.\n */\nexport const onlySampleIfChildSpans = (client: Client, span: Span): void => {\n if (!isRootSpan(span) || !isSentrySpan(span)) {\n debug.warn('Not sampling childless spans only works for Sentry Transactions (Root Spans).');\n return;\n }\n\n const unsubscribe = client.on('spanEnd', (endedSpan: Span) => {\n if (endedSpan !== span) {\n return;\n }\n unsubscribe();\n\n const children = getSpanDescendants(span);\n\n if (children.length <= 1) {\n // Span always has at lest one child, itself\n debug.log(`Not sampling as ${spanToJSON(span).op} transaction has no child spans.`);\n span['_sampled'] = false;\n }\n });\n};\n\n/**\n * Hooks on AppState change to cancel the span if the app goes background.\n *\n * On iOS the JS thread can be suspended between the `inactive` and\n * `background` transitions, which means the `background` event may never\n * reach JS in time. To handle this we schedule a deferred cancellation when\n * the app becomes `inactive`. If the app returns to `active` before the\n * timeout fires, the cancellation is cleared. If it transitions to\n * `background` first, we cancel immediately and clear the timeout.\n */\nexport const cancelInBackground = (client: Client, span: Span): void => {\n let inactiveTimeout: ReturnType<typeof setTimeout> | undefined;\n\n const cancelSpan = (): void => {\n if (inactiveTimeout !== undefined) {\n clearTimeout(inactiveTimeout);\n inactiveTimeout = undefined;\n }\n debug.log(`Setting ${spanToJSON(span).op} transaction to cancelled because the app is in the background.`);\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'cancelled' });\n span.end();\n };\n\n const subscription = AppState.addEventListener('change', (newState: AppStateStatus) => {\n if (newState === 'background') {\n cancelSpan();\n } else if (Platform.OS === 'ios' && newState === 'inactive') {\n // Schedule a deferred cancellation — if the JS thread is suspended\n // before the 'background' event fires, this timer will execute when\n // the app is eventually resumed and end the span.\n if (inactiveTimeout === undefined) {\n inactiveTimeout = setTimeout(cancelSpan, IOS_INACTIVE_CANCEL_DELAY_MS);\n }\n } else if (newState === 'active') {\n // App returned to foreground — clear any pending inactive cancellation.\n if (inactiveTimeout !== undefined) {\n clearTimeout(inactiveTimeout);\n inactiveTimeout = undefined;\n }\n }\n });\n\n if (subscription) {\n const unsubscribe = client.on('spanEnd', (endedSpan: Span) => {\n if (endedSpan !== span) {\n return;\n }\n unsubscribe();\n debug.log(`Removing AppState listener for ${spanToJSON(span).op} transaction.`);\n if (inactiveTimeout !== undefined) {\n clearTimeout(inactiveTimeout);\n inactiveTimeout = undefined;\n }\n subscription.remove?.();\n });\n }\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactnativenavigation.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/reactnativenavigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,WAAW,EAAQ,MAAM,cAAc,CAAC;AAS9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAazE,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AAIxD,UAAU,4BAA4B;IACpC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAEpC;;;;;OAKG;IACH,qCAAqC,CAAC,EAAE,OAAO,CAAC;IAEhD;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,cAAc;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,KAAK,aAAa,GAAG,WAAW,GAAG,aAAa,GAAG,kBAAkB,GAAG,cAAc,CAAC;AAEvF,MAAM,WAAW,wBAAyB,SAAQ,cAAc;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,mCAAmC,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,IAAI,GAAG,mBAAmB,CAAC;IAC9G,uBAAuB,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,iBAAiB,CAAC;IAC9F,gCAAgC,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,GAAG,mBAAmB,CAAC;CACzG;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,cAAc,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC
|
|
1
|
+
{"version":3,"file":"reactnativenavigation.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/reactnativenavigation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,WAAW,EAAQ,MAAM,cAAc,CAAC;AAS9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAazE,eAAO,MAAM,gBAAgB,0BAA0B,CAAC;AAIxD,UAAU,4BAA4B;IACpC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;OAKG;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IAEpC;;;;;OAKG;IACH,qCAAqC,CAAC,EAAE,OAAO,CAAC;IAEhD;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,cAAc;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,KAAK,aAAa,GAAG,WAAW,GAAG,aAAa,GAAG,kBAAkB,GAAG,cAAc,CAAC;AAEvF,MAAM,WAAW,wBAAyB,SAAQ,cAAc;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,aAAa,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,mCAAmC,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,IAAI,GAAG,mBAAmB,CAAC;IAC9G,uBAAuB,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,iBAAiB,CAAC;IAC9F,gCAAgC,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,GAAG,mBAAmB,CAAC;CACzG;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,cAAc,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC,GAAI,4HAK9C,4BAA4B,KAAG,WA0IjC,CAAC"}
|