@sentry/react-native 7.0.0-rc.1 → 7.0.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 +3 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/io/sentry/react/RNSentryModuleImpl.java +50 -5
- package/android/src/main/java/io/sentry/react/RNSentryVersion.java +1 -1
- package/android/src/newarch/java/io/sentry/react/RNSentryModule.java +5 -0
- package/dist/js/NativeRNSentry.d.ts +1 -0
- package/dist/js/NativeRNSentry.d.ts.map +1 -1
- package/dist/js/NativeRNSentry.js.map +1 -1
- package/dist/js/client.d.ts +2 -2
- package/dist/js/client.d.ts.map +1 -1
- package/dist/js/client.js +8 -8
- package/dist/js/client.js.map +1 -1
- package/dist/js/feedback/FeedbackWidget.js +12 -12
- package/dist/js/feedback/FeedbackWidget.js.map +1 -1
- package/dist/js/feedback/FeedbackWidgetManager.js +2 -2
- package/dist/js/feedback/FeedbackWidgetManager.js.map +1 -1
- package/dist/js/feedback/FeedbackWidgetProvider.js +3 -3
- package/dist/js/feedback/FeedbackWidgetProvider.js.map +1 -1
- package/dist/js/integrations/appRegistry.js +2 -2
- package/dist/js/integrations/appRegistry.js.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 +3 -3
- package/dist/js/integrations/debugsymbolicatorutils.js.map +1 -1
- package/dist/js/integrations/default.d.ts.map +1 -1
- package/dist/js/integrations/default.js +4 -1
- package/dist/js/integrations/default.js.map +1 -1
- package/dist/js/integrations/devicecontext.js +2 -2
- package/dist/js/integrations/devicecontext.js.map +1 -1
- package/dist/js/integrations/expocontext.d.ts.map +1 -1
- package/dist/js/integrations/expocontext.js +2 -2
- package/dist/js/integrations/expocontext.js.map +1 -1
- package/dist/js/integrations/exports.d.ts +1 -0
- package/dist/js/integrations/exports.d.ts.map +1 -1
- package/dist/js/integrations/exports.js +1 -0
- package/dist/js/integrations/exports.js.map +1 -1
- package/dist/js/integrations/logEnricherIntegration.d.ts +3 -0
- package/dist/js/integrations/logEnricherIntegration.d.ts.map +1 -0
- package/dist/js/integrations/logEnricherIntegration.js +65 -0
- package/dist/js/integrations/logEnricherIntegration.js.map +1 -0
- package/dist/js/integrations/modulesloader.js +2 -2
- package/dist/js/integrations/modulesloader.js.map +1 -1
- package/dist/js/integrations/reactnativeerrorhandlers.js +12 -12
- package/dist/js/integrations/reactnativeerrorhandlers.js.map +1 -1
- package/dist/js/integrations/reactnativeerrorhandlersutils.js +6 -6
- package/dist/js/integrations/reactnativeerrorhandlersutils.js.map +1 -1
- package/dist/js/integrations/sdkinfo.js +3 -3
- package/dist/js/integrations/sdkinfo.js.map +1 -1
- package/dist/js/integrations/spotlight.js +4 -4
- package/dist/js/integrations/spotlight.js.map +1 -1
- package/dist/js/integrations/viewhierarchy.js +2 -2
- package/dist/js/integrations/viewhierarchy.js.map +1 -1
- package/dist/js/options.d.ts +1 -1
- package/dist/js/options.d.ts.map +1 -1
- package/dist/js/options.js.map +1 -1
- package/dist/js/playground/modal.js +3 -3
- package/dist/js/playground/modal.js.map +1 -1
- package/dist/js/profiling/convertHermesProfile.js +5 -5
- package/dist/js/profiling/convertHermesProfile.js.map +1 -1
- package/dist/js/profiling/debugid.d.ts.map +1 -1
- package/dist/js/profiling/debugid.js +2 -2
- package/dist/js/profiling/debugid.js.map +1 -1
- package/dist/js/profiling/integration.js +13 -13
- package/dist/js/profiling/integration.js.map +1 -1
- package/dist/js/profiling/utils.js +3 -3
- package/dist/js/profiling/utils.js.map +1 -1
- package/dist/js/replay/CustomMask.js +3 -3
- package/dist/js/replay/CustomMask.js.map +1 -1
- package/dist/js/replay/mobilereplay.js +5 -5
- package/dist/js/replay/mobilereplay.js.map +1 -1
- package/dist/js/sdk.js +7 -7
- package/dist/js/sdk.js.map +1 -1
- package/dist/js/tools/ModulesCollector.js +12 -12
- package/dist/js/tools/ModulesCollector.js.map +1 -1
- package/dist/js/tools/enableLogger.js +1 -1
- package/dist/js/tools/enableLogger.js.map +1 -1
- package/dist/js/tools/metroMiddleware.js +6 -6
- package/dist/js/tools/metroMiddleware.js.map +1 -1
- package/dist/js/tools/metroconfig.js +2 -2
- package/dist/js/tools/metroconfig.js.map +1 -1
- package/dist/js/tools/sentryBabelTransformerUtils.d.ts.map +1 -1
- package/dist/js/tools/sentryBabelTransformerUtils.js +6 -6
- package/dist/js/tools/sentryBabelTransformerUtils.js.map +1 -1
- package/dist/js/tools/utils.d.ts.map +1 -1
- package/dist/js/tools/utils.js +39 -10
- package/dist/js/tools/utils.js.map +1 -1
- package/dist/js/tools/vendor/metro/utils.d.ts.map +1 -1
- package/dist/js/tools/vendor/metro/utils.js +28 -6
- package/dist/js/tools/vendor/metro/utils.js.map +1 -1
- package/dist/js/touchevents.js +3 -3
- package/dist/js/touchevents.js.map +1 -1
- package/dist/js/tracing/gesturetracing.js +5 -5
- package/dist/js/tracing/gesturetracing.js.map +1 -1
- package/dist/js/tracing/integrations/appStart.js +34 -34
- package/dist/js/tracing/integrations/appStart.js.map +1 -1
- package/dist/js/tracing/integrations/nativeFrames.js +14 -14
- package/dist/js/tracing/integrations/nativeFrames.js.map +1 -1
- package/dist/js/tracing/integrations/stalltracking.js +7 -7
- package/dist/js/tracing/integrations/stalltracking.js.map +1 -1
- package/dist/js/tracing/integrations/timeToDisplayIntegration.js +11 -11
- package/dist/js/tracing/integrations/timeToDisplayIntegration.js.map +1 -1
- package/dist/js/tracing/integrations/userInteraction.js +8 -8
- package/dist/js/tracing/integrations/userInteraction.js.map +1 -1
- package/dist/js/tracing/onSpanEndUtils.js +10 -10
- package/dist/js/tracing/onSpanEndUtils.js.map +1 -1
- package/dist/js/tracing/reactnativeprofiler.js +2 -2
- package/dist/js/tracing/reactnativeprofiler.js.map +1 -1
- package/dist/js/tracing/reactnavigation.js +14 -14
- package/dist/js/tracing/reactnavigation.js.map +1 -1
- package/dist/js/tracing/span.js +6 -6
- package/dist/js/tracing/span.js.map +1 -1
- package/dist/js/tracing/timetodisplay.d.ts.map +1 -1
- package/dist/js/tracing/timetodisplay.js +20 -30
- package/dist/js/tracing/timetodisplay.js.map +1 -1
- package/dist/js/tracing/utils.js +2 -2
- package/dist/js/tracing/utils.js.map +1 -1
- package/dist/js/utils/environment.d.ts.map +1 -1
- package/dist/js/utils/environment.js +2 -1
- package/dist/js/utils/environment.js.map +1 -1
- package/dist/js/utils/safe.js +3 -3
- package/dist/js/utils/safe.js.map +1 -1
- package/dist/js/utils/worldwide.d.ts +1 -0
- package/dist/js/utils/worldwide.d.ts.map +1 -1
- package/dist/js/utils/worldwide.js.map +1 -1
- package/dist/js/version.d.ts +1 -1
- package/dist/js/version.d.ts.map +1 -1
- package/dist/js/version.js +1 -1
- package/dist/js/version.js.map +1 -1
- package/dist/js/wrapper.d.ts +1 -0
- package/dist/js/wrapper.d.ts.map +1 -1
- package/dist/js/wrapper.js +40 -26
- package/dist/js/wrapper.js.map +1 -1
- package/ios/RNSentry+fetchNativeStack.m +101 -0
- package/ios/RNSentry.h +5 -0
- package/ios/RNSentry.mm +67 -77
- package/ios/RNSentryVersion.m +1 -1
- package/package.json +15 -14
- package/plugin/build/withSentryAndroid.js +7 -7
- package/plugin/build/withSentryAndroidGradlePlugin.d.ts +3 -2
- package/plugin/build/withSentryAndroidGradlePlugin.js +11 -22
- package/scripts/expo-upload-sourcemaps.js +1 -1
- package/scripts/sentry_utils.rb +4 -0
- package/src/js/NativeRNSentry.ts +1 -0
- package/ts3.8/dist/js/NativeRNSentry.d.ts +1 -0
- package/ts3.8/dist/js/client.d.ts +2 -2
- package/ts3.8/dist/js/integrations/exports.d.ts +1 -0
- package/ts3.8/dist/js/integrations/logEnricherIntegration.d.ts +3 -0
- package/ts3.8/dist/js/options.d.ts +1 -1
- package/ts3.8/dist/js/utils/worldwide.d.ts +1 -0
- package/ts3.8/dist/js/version.d.ts +1 -1
- package/ts3.8/dist/js/wrapper.d.ts +1 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addBreadcrumb, getClient, isPlainObject,
|
|
1
|
+
import { addBreadcrumb, debug, getClient, isPlainObject, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_STATUS_OK, spanToJSON, startInactiveSpan, timestampInSeconds, } from '@sentry/core';
|
|
2
2
|
import { getAppRegistryIntegration } from '../integrations/appRegistry';
|
|
3
3
|
import { isSentrySpan } from '../utils/span';
|
|
4
4
|
import { RN_GLOBAL_OBJ } from '../utils/worldwide';
|
|
@@ -31,7 +31,7 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
|
|
|
31
31
|
let recentRouteKeys = [];
|
|
32
32
|
if (enableTimeToInitialDisplay) {
|
|
33
33
|
NATIVE.initNativeReactNavigationNewFrameTracking().catch((reason) => {
|
|
34
|
-
|
|
34
|
+
debug.error(`${INTEGRATION_NAME} Failed to initialize native new frame tracking: ${reason}`);
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
/**
|
|
@@ -57,7 +57,7 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
|
|
|
57
57
|
// To avoid conflict with the initial transaction we check if it was already handled.
|
|
58
58
|
// This ensures runApplication calls after the initial start are correctly traced.
|
|
59
59
|
// This is used for example when Activity is (re)started on Android.
|
|
60
|
-
|
|
60
|
+
debug.log('[ReactNavigationIntegration] Starting new idle navigation span based on runApplication call.');
|
|
61
61
|
startIdleNavigationSpan();
|
|
62
62
|
}
|
|
63
63
|
});
|
|
@@ -72,7 +72,7 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
|
|
|
72
72
|
};
|
|
73
73
|
const registerNavigationContainer = (maybeNewNavigationContainer) => {
|
|
74
74
|
if (RN_GLOBAL_OBJ.__sentry_rn_v5_registered) {
|
|
75
|
-
|
|
75
|
+
debug.log(`${INTEGRATION_NAME} Instrumentation already exists, but registering again...`);
|
|
76
76
|
// In the past we have not allowed re-registering the navigation container to avoid unexpected behavior.
|
|
77
77
|
// But this doesn't work for Android and re-recreating application main activity.
|
|
78
78
|
// Where new navigation container is created and the old one is discarded. We need to re-register to
|
|
@@ -86,12 +86,12 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
|
|
|
86
86
|
newNavigationContainer = maybeNewNavigationContainer;
|
|
87
87
|
}
|
|
88
88
|
if (navigationContainer === newNavigationContainer) {
|
|
89
|
-
|
|
89
|
+
debug.log(`${INTEGRATION_NAME} Navigation container ref is the same as the one already registered.`);
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
92
|
navigationContainer = newNavigationContainer;
|
|
93
93
|
if (!navigationContainer) {
|
|
94
|
-
|
|
94
|
+
debug.warn(`${INTEGRATION_NAME} Received invalid navigation container ref!`);
|
|
95
95
|
return undefined;
|
|
96
96
|
}
|
|
97
97
|
// This action is emitted on every dispatch
|
|
@@ -102,7 +102,7 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
|
|
|
102
102
|
return undefined;
|
|
103
103
|
}
|
|
104
104
|
if (!latestNavigationSpan) {
|
|
105
|
-
|
|
105
|
+
debug.log(`${INTEGRATION_NAME} Navigation container registered, but integration has not been setup yet.`);
|
|
106
106
|
return undefined;
|
|
107
107
|
}
|
|
108
108
|
// Navigation Container is registered after the first navigation
|
|
@@ -119,7 +119,7 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
|
|
|
119
119
|
const startIdleNavigationSpan = (unknownEvent) => {
|
|
120
120
|
const event = unknownEvent;
|
|
121
121
|
if (useDispatchedActionData && (event === null || event === void 0 ? void 0 : event.data.noop)) {
|
|
122
|
-
|
|
122
|
+
debug.log(`${INTEGRATION_NAME} Navigation action is a noop, not starting navigation span.`);
|
|
123
123
|
return;
|
|
124
124
|
}
|
|
125
125
|
const navigationActionType = useDispatchedActionData ? event === null || event === void 0 ? void 0 : event.data.action.type : undefined;
|
|
@@ -134,11 +134,11 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
|
|
|
134
134
|
'CLOSE_DRAWER',
|
|
135
135
|
'TOGGLE_DRAWER',
|
|
136
136
|
].includes(navigationActionType)) {
|
|
137
|
-
|
|
137
|
+
debug.log(`${INTEGRATION_NAME} Navigation action is ${navigationActionType}, not starting navigation span.`);
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
140
140
|
if (latestNavigationSpan) {
|
|
141
|
-
|
|
141
|
+
debug.log(`${INTEGRATION_NAME} A transaction was detected that turned out to be a noop, discarding.`);
|
|
142
142
|
_discardLatestTransaction();
|
|
143
143
|
clearStateChangeTimeout();
|
|
144
144
|
}
|
|
@@ -168,21 +168,21 @@ export const reactNavigationIntegration = ({ routeChangeTimeoutMs = 1000, enable
|
|
|
168
168
|
const stateChangedTimestamp = timestampInSeconds();
|
|
169
169
|
const previousRoute = latestRoute;
|
|
170
170
|
if (!navigationContainer) {
|
|
171
|
-
|
|
171
|
+
debug.warn(`${INTEGRATION_NAME} Missing navigation container ref. Route transactions will not be sent.`);
|
|
172
172
|
return undefined;
|
|
173
173
|
}
|
|
174
174
|
const route = navigationContainer.getCurrentRoute();
|
|
175
175
|
if (!route) {
|
|
176
|
-
|
|
176
|
+
debug.log(`[${INTEGRATION_NAME}] Navigation state changed, but no route is rendered.`);
|
|
177
177
|
return undefined;
|
|
178
178
|
}
|
|
179
179
|
if (!latestNavigationSpan) {
|
|
180
|
-
|
|
180
|
+
debug.log(`[${INTEGRATION_NAME}] Navigation state changed, but navigation transaction was not started on dispatch.`);
|
|
181
181
|
return undefined;
|
|
182
182
|
}
|
|
183
183
|
addTimeToInitialDisplayFallback(latestNavigationSpan.spanContext().spanId, NATIVE.getNewScreenTimeToDisplay());
|
|
184
184
|
if (previousRoute && previousRoute.key === route.key) {
|
|
185
|
-
|
|
185
|
+
debug.log(`[${INTEGRATION_NAME}] Navigation state changed, but route is the same as previous.`);
|
|
186
186
|
pushRecentRouteKey(route.key);
|
|
187
187
|
latestRoute = route;
|
|
188
188
|
// Clear the latest transaction as it has been handled.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactnavigation.js","sourceRoot":"","sources":["../../../src/js/tracing/reactnavigation.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Integration, Span } from '@sentry/core';\nimport {\n addBreadcrumb,\n getClient,\n isPlainObject,\n logger,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_OK,\n spanToJSON,\n startInactiveSpan,\n timestampInSeconds,\n} from '@sentry/core';\nimport { getAppRegistryIntegration } from '../integrations/appRegistry';\nimport { isSentrySpan } from '../utils/span';\nimport { RN_GLOBAL_OBJ } from '../utils/worldwide';\nimport type { UnsafeAction } from '../vendor/react-navigation/types';\nimport { NATIVE } from '../wrapper';\nimport { ignoreEmptyBackNavigation } from './onSpanEndUtils';\nimport { SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION } from './origin';\nimport type { ReactNativeTracingIntegration } from './reactnativetracing';\nimport { getReactNativeTracingIntegration } from './reactnativetracing';\nimport { SEMANTIC_ATTRIBUTE_NAVIGATION_ACTION_TYPE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from './semanticAttributes';\nimport {\n DEFAULT_NAVIGATION_SPAN_NAME,\n defaultIdleOptions,\n getDefaultIdleNavigationSpanOptions,\n startIdleNavigationSpan as startGenericIdleNavigationSpan,\n} from './span';\nimport { addTimeToInitialDisplayFallback } from './timeToDisplayFallback';\n\nexport const INTEGRATION_NAME = 'ReactNavigation';\n\nconst NAVIGATION_HISTORY_MAX_SIZE = 200;\n\ninterface ReactNavigationIntegrationOptions {\n /**\n * How long the instrumentation will wait for the route to mount after a change has been initiated,\n * before the transaction is discarded.\n *\n * @default 1_000 (ms)\n */\n routeChangeTimeoutMs: number;\n\n /**\n * Time to initial display measures the time it takes from\n * navigation dispatch to the render of the first frame of the new screen.\n *\n * @default false\n */\n enableTimeToInitialDisplay: boolean;\n\n /**\n * Does not sample transactions that are from routes that have been seen any more and don't have any spans.\n * This removes a lot of the clutter as most back navigation transactions are now ignored.\n *\n * @default true\n */\n ignoreEmptyBackNavigationTransactions: boolean;\n\n /**\n * Enabled measuring Time to Initial Display for routes that are already loaded in memory.\n * (a.k.a., Routes that the navigation integration has already seen.)\n *\n * @default false\n */\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n\n /**\n * Whether to use the dispatched action data to populate the transaction metadata.\n *\n * @default false\n */\n useDispatchedActionData: boolean;\n}\n\n/**\n * Instrumentation for React-Navigation V5 and above. See docs or sample app for usage.\n *\n * How this works:\n * - `_onDispatch` is called every time a dispatch happens and sets an IdleTransaction on the scope without any route context.\n * - `_onStateChange` is then called AFTER the state change happens due to a dispatch and sets the route context onto the active transaction.\n * - If `_onStateChange` isn't called within `STATE_CHANGE_TIMEOUT_DURATION` of the dispatch, then the transaction is not sampled and finished.\n */\nexport const reactNavigationIntegration = ({\n routeChangeTimeoutMs = 1_000,\n enableTimeToInitialDisplay = false,\n ignoreEmptyBackNavigationTransactions = true,\n enableTimeToInitialDisplayForPreloadedRoutes = false,\n useDispatchedActionData = false,\n}: Partial<ReactNavigationIntegrationOptions> = {}): Integration & {\n /**\n * Pass the ref to the navigation container to register it to the instrumentation\n * @param navigationContainerRef Ref to a `NavigationContainer`\n */\n registerNavigationContainer: (navigationContainerRef: unknown) => void;\n options: ReactNavigationIntegrationOptions;\n} => {\n let navigationContainer: NavigationContainer | undefined;\n\n let tracing: ReactNativeTracingIntegration | undefined;\n let idleSpanOptions: Parameters<typeof startGenericIdleNavigationSpan>[1] = defaultIdleOptions;\n let latestRoute: NavigationRoute | undefined;\n\n let latestNavigationSpan: Span | undefined;\n let navigationProcessingSpan: Span | undefined;\n\n let initialStateHandled: boolean = false;\n let stateChangeTimeout: ReturnType<typeof setTimeout> | undefined;\n let recentRouteKeys: string[] = [];\n\n if (enableTimeToInitialDisplay) {\n NATIVE.initNativeReactNavigationNewFrameTracking().catch((reason: unknown) => {\n logger.error(`${INTEGRATION_NAME} Failed to initialize native new frame tracking: ${reason}`);\n });\n }\n\n /**\n * Set the initial state and start initial navigation span for the current screen.\n */\n const afterAllSetup = (client: Client): void => {\n tracing = getReactNativeTracingIntegration(client);\n if (tracing) {\n idleSpanOptions = {\n finalTimeout: tracing.options.finalTimeoutMs,\n idleTimeout: tracing.options.idleTimeoutMs,\n };\n }\n\n if (initialStateHandled) {\n // We create an initial state here to ensure a transaction gets created before the first route mounts.\n // This assumes that the Sentry.init() call is made before the first route mounts.\n // If this is not the case, the first transaction will be nameless 'Route Changed'\n return undefined;\n }\n\n getAppRegistryIntegration(client)?.onRunApplication(() => {\n if (initialStateHandled) {\n // To avoid conflict with the initial transaction we check if it was already handled.\n // This ensures runApplication calls after the initial start are correctly traced.\n // This is used for example when Activity is (re)started on Android.\n logger.log('[ReactNavigationIntegration] Starting new idle navigation span based on runApplication call.');\n startIdleNavigationSpan();\n }\n });\n\n startIdleNavigationSpan();\n\n if (!navigationContainer) {\n // This is expected as navigation container is registered after the root component is mounted.\n return undefined;\n }\n\n // Navigation container already registered, just populate with route state\n updateLatestNavigationSpanWithCurrentRoute();\n initialStateHandled = true;\n };\n\n const registerNavigationContainer = (maybeNewNavigationContainer: unknown): void => {\n if (RN_GLOBAL_OBJ.__sentry_rn_v5_registered) {\n logger.debug(`${INTEGRATION_NAME} Instrumentation already exists, but registering again...`);\n // In the past we have not allowed re-registering the navigation container to avoid unexpected behavior.\n // But this doesn't work for Android and re-recreating application main activity.\n // Where new navigation container is created and the old one is discarded. We need to re-register to\n // trace the new navigation container navigation.\n }\n\n let newNavigationContainer: NavigationContainer | undefined;\n if (isPlainObject(maybeNewNavigationContainer) && 'current' in maybeNewNavigationContainer) {\n newNavigationContainer = maybeNewNavigationContainer.current as NavigationContainer;\n } else {\n newNavigationContainer = maybeNewNavigationContainer as NavigationContainer;\n }\n\n if (navigationContainer === newNavigationContainer) {\n logger.log(`${INTEGRATION_NAME} Navigation container ref is the same as the one already registered.`);\n return;\n }\n navigationContainer = newNavigationContainer as NavigationContainer;\n\n if (!navigationContainer) {\n logger.warn(`${INTEGRATION_NAME} Received invalid navigation container ref!`);\n return undefined;\n }\n\n // This action is emitted on every dispatch\n navigationContainer.addListener('__unsafe_action__', startIdleNavigationSpan);\n navigationContainer.addListener('state', updateLatestNavigationSpanWithCurrentRoute);\n RN_GLOBAL_OBJ.__sentry_rn_v5_registered = true;\n\n if (initialStateHandled) {\n return undefined;\n }\n\n if (!latestNavigationSpan) {\n logger.log(`${INTEGRATION_NAME} Navigation container registered, but integration has not been setup yet.`);\n return undefined;\n }\n\n // Navigation Container is registered after the first navigation\n // Initial navigation span was started, after integration setup,\n // so now we populate it with the current route.\n updateLatestNavigationSpanWithCurrentRoute();\n initialStateHandled = true;\n };\n\n /**\n * To be called on every React-Navigation action dispatch.\n * It does not name the transaction or populate it with route information. Instead, it waits for the state to fully change\n * and gets the route information from there, @see updateLatestNavigationSpanWithCurrentRoute\n */\n const startIdleNavigationSpan = (unknownEvent?: unknown): void => {\n const event = unknownEvent as UnsafeAction | undefined;\n if (useDispatchedActionData && event?.data.noop) {\n logger.debug(`${INTEGRATION_NAME} Navigation action is a noop, not starting navigation span.`);\n return;\n }\n\n const navigationActionType = useDispatchedActionData ? event?.data.action.type : undefined;\n if (\n useDispatchedActionData &&\n navigationActionType &&\n [\n // Process common actions\n 'PRELOAD',\n 'SET_PARAMS',\n // Drawer actions\n 'OPEN_DRAWER',\n 'CLOSE_DRAWER',\n 'TOGGLE_DRAWER',\n ].includes(navigationActionType)\n ) {\n logger.debug(`${INTEGRATION_NAME} Navigation action is ${navigationActionType}, not starting navigation span.`);\n return;\n }\n\n if (latestNavigationSpan) {\n logger.log(`${INTEGRATION_NAME} A transaction was detected that turned out to be a noop, discarding.`);\n _discardLatestTransaction();\n clearStateChangeTimeout();\n }\n\n latestNavigationSpan = startGenericIdleNavigationSpan(\n tracing?.options.beforeStartSpan\n ? tracing.options.beforeStartSpan(getDefaultIdleNavigationSpanOptions())\n : getDefaultIdleNavigationSpanOptions(),\n idleSpanOptions,\n );\n latestNavigationSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION);\n latestNavigationSpan?.setAttribute(SEMANTIC_ATTRIBUTE_NAVIGATION_ACTION_TYPE, navigationActionType);\n if (ignoreEmptyBackNavigationTransactions) {\n ignoreEmptyBackNavigation(getClient(), latestNavigationSpan);\n }\n\n if (enableTimeToInitialDisplay && latestNavigationSpan) {\n NATIVE.setActiveSpanId(latestNavigationSpan.spanContext().spanId);\n navigationProcessingSpan = startInactiveSpan({\n op: 'navigation.processing',\n name: 'Navigation dispatch to navigation cancelled or screen mounted',\n startTime: spanToJSON(latestNavigationSpan).start_timestamp,\n });\n navigationProcessingSpan.setAttribute(\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION,\n );\n }\n\n stateChangeTimeout = setTimeout(_discardLatestTransaction, routeChangeTimeoutMs);\n };\n\n /**\n * To be called AFTER the state has been changed to populate the transaction with the current route.\n */\n const updateLatestNavigationSpanWithCurrentRoute = (): void => {\n const stateChangedTimestamp = timestampInSeconds();\n const previousRoute = latestRoute;\n\n if (!navigationContainer) {\n logger.warn(`${INTEGRATION_NAME} Missing navigation container ref. Route transactions will not be sent.`);\n return undefined;\n }\n\n const route = navigationContainer.getCurrentRoute();\n if (!route) {\n logger.debug(`[${INTEGRATION_NAME}] Navigation state changed, but no route is rendered.`);\n return undefined;\n }\n\n if (!latestNavigationSpan) {\n logger.debug(\n `[${INTEGRATION_NAME}] Navigation state changed, but navigation transaction was not started on dispatch.`,\n );\n return undefined;\n }\n\n addTimeToInitialDisplayFallback(latestNavigationSpan.spanContext().spanId, NATIVE.getNewScreenTimeToDisplay());\n\n if (previousRoute && previousRoute.key === route.key) {\n logger.debug(`[${INTEGRATION_NAME}] Navigation state changed, but route is the same as previous.`);\n pushRecentRouteKey(route.key);\n latestRoute = route;\n\n // Clear the latest transaction as it has been handled.\n latestNavigationSpan = undefined;\n return undefined;\n }\n\n const routeHasBeenSeen = recentRouteKeys.includes(route.key);\n\n navigationProcessingSpan?.updateName(`Navigation dispatch to screen ${route.name} mounted`);\n navigationProcessingSpan?.setStatus({ code: SPAN_STATUS_OK });\n navigationProcessingSpan?.end(stateChangedTimestamp);\n navigationProcessingSpan = undefined;\n\n if (spanToJSON(latestNavigationSpan).description === DEFAULT_NAVIGATION_SPAN_NAME) {\n latestNavigationSpan.updateName(route.name);\n }\n latestNavigationSpan.setAttributes({\n 'route.name': route.name,\n 'route.key': route.key,\n // TODO: filter PII params instead of dropping them all\n // 'route.params': {},\n 'route.has_been_seen': routeHasBeenSeen,\n 'previous_route.name': previousRoute?.name,\n 'previous_route.key': previousRoute?.key,\n // TODO: filter PII params instead of dropping them all\n // 'previous_route.params': {},\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n });\n\n // Clear the timeout so the transaction does not get cancelled.\n clearStateChangeTimeout();\n\n addBreadcrumb({\n category: 'navigation',\n type: 'navigation',\n message: `Navigation to ${route.name}`,\n data: {\n from: previousRoute?.name,\n to: route.name,\n },\n });\n\n tracing?.setCurrentRoute(route.name);\n\n pushRecentRouteKey(route.key);\n latestRoute = route;\n // Clear the latest transaction as it has been handled.\n latestNavigationSpan = undefined;\n };\n\n /** Pushes a recent route key, and removes earlier routes when there is greater than the max length */\n const pushRecentRouteKey = (key: string): void => {\n recentRouteKeys.push(key);\n\n if (recentRouteKeys.length > NAVIGATION_HISTORY_MAX_SIZE) {\n recentRouteKeys = recentRouteKeys.slice(recentRouteKeys.length - NAVIGATION_HISTORY_MAX_SIZE);\n }\n };\n\n /** Cancels the latest transaction so it does not get sent to Sentry. */\n const _discardLatestTransaction = (): void => {\n if (latestNavigationSpan) {\n if (isSentrySpan(latestNavigationSpan)) {\n latestNavigationSpan['_sampled'] = false;\n }\n // TODO: What if it's not SentrySpan?\n latestNavigationSpan.end();\n latestNavigationSpan = undefined;\n }\n if (navigationProcessingSpan) {\n navigationProcessingSpan = undefined;\n }\n };\n\n const clearStateChangeTimeout = (): void => {\n if (typeof stateChangeTimeout !== 'undefined') {\n clearTimeout(stateChangeTimeout);\n stateChangeTimeout = undefined;\n }\n };\n\n return {\n name: INTEGRATION_NAME,\n afterAllSetup,\n registerNavigationContainer,\n options: {\n routeChangeTimeoutMs,\n enableTimeToInitialDisplay,\n ignoreEmptyBackNavigationTransactions,\n enableTimeToInitialDisplayForPreloadedRoutes,\n useDispatchedActionData,\n },\n };\n};\n\nexport interface NavigationRoute {\n name: string;\n key: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n params?: Record<string, any>;\n}\n\ninterface NavigationContainer {\n addListener: (type: string, listener: (event?: unknown) => void) => void;\n getCurrentRoute: () => NavigationRoute;\n}\n\n/**\n * Returns React Navigation integration of the given client.\n */\nexport function getReactNavigationIntegration(\n client: Client,\n): ReturnType<typeof reactNavigationIntegration> | undefined {\n return client.getIntegrationByName<ReturnType<typeof reactNavigationIntegration>>(INTEGRATION_NAME);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"reactnavigation.js","sourceRoot":"","sources":["../../../src/js/tracing/reactnavigation.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable max-lines */\nimport type { Client, Integration, Span } from '@sentry/core';\nimport {\n addBreadcrumb,\n debug,\n getClient,\n isPlainObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_OK,\n spanToJSON,\n startInactiveSpan,\n timestampInSeconds,\n} from '@sentry/core';\nimport { getAppRegistryIntegration } from '../integrations/appRegistry';\nimport { isSentrySpan } from '../utils/span';\nimport { RN_GLOBAL_OBJ } from '../utils/worldwide';\nimport type { UnsafeAction } from '../vendor/react-navigation/types';\nimport { NATIVE } from '../wrapper';\nimport { ignoreEmptyBackNavigation } from './onSpanEndUtils';\nimport { SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION } from './origin';\nimport type { ReactNativeTracingIntegration } from './reactnativetracing';\nimport { getReactNativeTracingIntegration } from './reactnativetracing';\nimport { SEMANTIC_ATTRIBUTE_NAVIGATION_ACTION_TYPE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from './semanticAttributes';\nimport {\n DEFAULT_NAVIGATION_SPAN_NAME,\n defaultIdleOptions,\n getDefaultIdleNavigationSpanOptions,\n startIdleNavigationSpan as startGenericIdleNavigationSpan,\n} from './span';\nimport { addTimeToInitialDisplayFallback } from './timeToDisplayFallback';\n\nexport const INTEGRATION_NAME = 'ReactNavigation';\n\nconst NAVIGATION_HISTORY_MAX_SIZE = 200;\n\ninterface ReactNavigationIntegrationOptions {\n /**\n * How long the instrumentation will wait for the route to mount after a change has been initiated,\n * before the transaction is discarded.\n *\n * @default 1_000 (ms)\n */\n routeChangeTimeoutMs: number;\n\n /**\n * Time to initial display measures the time it takes from\n * navigation dispatch to the render of the first frame of the new screen.\n *\n * @default false\n */\n enableTimeToInitialDisplay: boolean;\n\n /**\n * Does not sample transactions that are from routes that have been seen any more and don't have any spans.\n * This removes a lot of the clutter as most back navigation transactions are now ignored.\n *\n * @default true\n */\n ignoreEmptyBackNavigationTransactions: boolean;\n\n /**\n * Enabled measuring Time to Initial Display for routes that are already loaded in memory.\n * (a.k.a., Routes that the navigation integration has already seen.)\n *\n * @default false\n */\n enableTimeToInitialDisplayForPreloadedRoutes: boolean;\n\n /**\n * Whether to use the dispatched action data to populate the transaction metadata.\n *\n * @default false\n */\n useDispatchedActionData: boolean;\n}\n\n/**\n * Instrumentation for React-Navigation V5 and above. See docs or sample app for usage.\n *\n * How this works:\n * - `_onDispatch` is called every time a dispatch happens and sets an IdleTransaction on the scope without any route context.\n * - `_onStateChange` is then called AFTER the state change happens due to a dispatch and sets the route context onto the active transaction.\n * - If `_onStateChange` isn't called within `STATE_CHANGE_TIMEOUT_DURATION` of the dispatch, then the transaction is not sampled and finished.\n */\nexport const reactNavigationIntegration = ({\n routeChangeTimeoutMs = 1_000,\n enableTimeToInitialDisplay = false,\n ignoreEmptyBackNavigationTransactions = true,\n enableTimeToInitialDisplayForPreloadedRoutes = false,\n useDispatchedActionData = false,\n}: Partial<ReactNavigationIntegrationOptions> = {}): Integration & {\n /**\n * Pass the ref to the navigation container to register it to the instrumentation\n * @param navigationContainerRef Ref to a `NavigationContainer`\n */\n registerNavigationContainer: (navigationContainerRef: unknown) => void;\n options: ReactNavigationIntegrationOptions;\n} => {\n let navigationContainer: NavigationContainer | undefined;\n\n let tracing: ReactNativeTracingIntegration | undefined;\n let idleSpanOptions: Parameters<typeof startGenericIdleNavigationSpan>[1] = defaultIdleOptions;\n let latestRoute: NavigationRoute | undefined;\n\n let latestNavigationSpan: Span | undefined;\n let navigationProcessingSpan: Span | undefined;\n\n let initialStateHandled: boolean = false;\n let stateChangeTimeout: ReturnType<typeof setTimeout> | undefined;\n let recentRouteKeys: string[] = [];\n\n if (enableTimeToInitialDisplay) {\n NATIVE.initNativeReactNavigationNewFrameTracking().catch((reason: unknown) => {\n debug.error(`${INTEGRATION_NAME} Failed to initialize native new frame tracking: ${reason}`);\n });\n }\n\n /**\n * Set the initial state and start initial navigation span for the current screen.\n */\n const afterAllSetup = (client: Client): void => {\n tracing = getReactNativeTracingIntegration(client);\n if (tracing) {\n idleSpanOptions = {\n finalTimeout: tracing.options.finalTimeoutMs,\n idleTimeout: tracing.options.idleTimeoutMs,\n };\n }\n\n if (initialStateHandled) {\n // We create an initial state here to ensure a transaction gets created before the first route mounts.\n // This assumes that the Sentry.init() call is made before the first route mounts.\n // If this is not the case, the first transaction will be nameless 'Route Changed'\n return undefined;\n }\n\n getAppRegistryIntegration(client)?.onRunApplication(() => {\n if (initialStateHandled) {\n // To avoid conflict with the initial transaction we check if it was already handled.\n // This ensures runApplication calls after the initial start are correctly traced.\n // This is used for example when Activity is (re)started on Android.\n debug.log('[ReactNavigationIntegration] Starting new idle navigation span based on runApplication call.');\n startIdleNavigationSpan();\n }\n });\n\n startIdleNavigationSpan();\n\n if (!navigationContainer) {\n // This is expected as navigation container is registered after the root component is mounted.\n return undefined;\n }\n\n // Navigation container already registered, just populate with route state\n updateLatestNavigationSpanWithCurrentRoute();\n initialStateHandled = true;\n };\n\n const registerNavigationContainer = (maybeNewNavigationContainer: unknown): void => {\n if (RN_GLOBAL_OBJ.__sentry_rn_v5_registered) {\n debug.log(`${INTEGRATION_NAME} Instrumentation already exists, but registering again...`);\n // In the past we have not allowed re-registering the navigation container to avoid unexpected behavior.\n // But this doesn't work for Android and re-recreating application main activity.\n // Where new navigation container is created and the old one is discarded. We need to re-register to\n // trace the new navigation container navigation.\n }\n\n let newNavigationContainer: NavigationContainer | undefined;\n if (isPlainObject(maybeNewNavigationContainer) && 'current' in maybeNewNavigationContainer) {\n newNavigationContainer = maybeNewNavigationContainer.current as NavigationContainer;\n } else {\n newNavigationContainer = maybeNewNavigationContainer as NavigationContainer;\n }\n\n if (navigationContainer === newNavigationContainer) {\n debug.log(`${INTEGRATION_NAME} Navigation container ref is the same as the one already registered.`);\n return;\n }\n navigationContainer = newNavigationContainer as NavigationContainer;\n\n if (!navigationContainer) {\n debug.warn(`${INTEGRATION_NAME} Received invalid navigation container ref!`);\n return undefined;\n }\n\n // This action is emitted on every dispatch\n navigationContainer.addListener('__unsafe_action__', startIdleNavigationSpan);\n navigationContainer.addListener('state', updateLatestNavigationSpanWithCurrentRoute);\n RN_GLOBAL_OBJ.__sentry_rn_v5_registered = true;\n\n if (initialStateHandled) {\n return undefined;\n }\n\n if (!latestNavigationSpan) {\n debug.log(`${INTEGRATION_NAME} Navigation container registered, but integration has not been setup yet.`);\n return undefined;\n }\n\n // Navigation Container is registered after the first navigation\n // Initial navigation span was started, after integration setup,\n // so now we populate it with the current route.\n updateLatestNavigationSpanWithCurrentRoute();\n initialStateHandled = true;\n };\n\n /**\n * To be called on every React-Navigation action dispatch.\n * It does not name the transaction or populate it with route information. Instead, it waits for the state to fully change\n * and gets the route information from there, @see updateLatestNavigationSpanWithCurrentRoute\n */\n const startIdleNavigationSpan = (unknownEvent?: unknown): void => {\n const event = unknownEvent as UnsafeAction | undefined;\n if (useDispatchedActionData && event?.data.noop) {\n debug.log(`${INTEGRATION_NAME} Navigation action is a noop, not starting navigation span.`);\n return;\n }\n\n const navigationActionType = useDispatchedActionData ? event?.data.action.type : undefined;\n if (\n useDispatchedActionData &&\n navigationActionType &&\n [\n // Process common actions\n 'PRELOAD',\n 'SET_PARAMS',\n // Drawer actions\n 'OPEN_DRAWER',\n 'CLOSE_DRAWER',\n 'TOGGLE_DRAWER',\n ].includes(navigationActionType)\n ) {\n debug.log(`${INTEGRATION_NAME} Navigation action is ${navigationActionType}, not starting navigation span.`);\n return;\n }\n\n if (latestNavigationSpan) {\n debug.log(`${INTEGRATION_NAME} A transaction was detected that turned out to be a noop, discarding.`);\n _discardLatestTransaction();\n clearStateChangeTimeout();\n }\n\n latestNavigationSpan = startGenericIdleNavigationSpan(\n tracing?.options.beforeStartSpan\n ? tracing.options.beforeStartSpan(getDefaultIdleNavigationSpanOptions())\n : getDefaultIdleNavigationSpanOptions(),\n idleSpanOptions,\n );\n latestNavigationSpan?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION);\n latestNavigationSpan?.setAttribute(SEMANTIC_ATTRIBUTE_NAVIGATION_ACTION_TYPE, navigationActionType);\n if (ignoreEmptyBackNavigationTransactions) {\n ignoreEmptyBackNavigation(getClient(), latestNavigationSpan);\n }\n\n if (enableTimeToInitialDisplay && latestNavigationSpan) {\n NATIVE.setActiveSpanId(latestNavigationSpan.spanContext().spanId);\n navigationProcessingSpan = startInactiveSpan({\n op: 'navigation.processing',\n name: 'Navigation dispatch to navigation cancelled or screen mounted',\n startTime: spanToJSON(latestNavigationSpan).start_timestamp,\n });\n navigationProcessingSpan.setAttribute(\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_ORIGIN_AUTO_NAVIGATION_REACT_NAVIGATION,\n );\n }\n\n stateChangeTimeout = setTimeout(_discardLatestTransaction, routeChangeTimeoutMs);\n };\n\n /**\n * To be called AFTER the state has been changed to populate the transaction with the current route.\n */\n const updateLatestNavigationSpanWithCurrentRoute = (): void => {\n const stateChangedTimestamp = timestampInSeconds();\n const previousRoute = latestRoute;\n\n if (!navigationContainer) {\n debug.warn(`${INTEGRATION_NAME} Missing navigation container ref. Route transactions will not be sent.`);\n return undefined;\n }\n\n const route = navigationContainer.getCurrentRoute();\n if (!route) {\n debug.log(`[${INTEGRATION_NAME}] Navigation state changed, but no route is rendered.`);\n return undefined;\n }\n\n if (!latestNavigationSpan) {\n debug.log(\n `[${INTEGRATION_NAME}] Navigation state changed, but navigation transaction was not started on dispatch.`,\n );\n return undefined;\n }\n\n addTimeToInitialDisplayFallback(latestNavigationSpan.spanContext().spanId, NATIVE.getNewScreenTimeToDisplay());\n\n if (previousRoute && previousRoute.key === route.key) {\n debug.log(`[${INTEGRATION_NAME}] Navigation state changed, but route is the same as previous.`);\n pushRecentRouteKey(route.key);\n latestRoute = route;\n\n // Clear the latest transaction as it has been handled.\n latestNavigationSpan = undefined;\n return undefined;\n }\n\n const routeHasBeenSeen = recentRouteKeys.includes(route.key);\n\n navigationProcessingSpan?.updateName(`Navigation dispatch to screen ${route.name} mounted`);\n navigationProcessingSpan?.setStatus({ code: SPAN_STATUS_OK });\n navigationProcessingSpan?.end(stateChangedTimestamp);\n navigationProcessingSpan = undefined;\n\n if (spanToJSON(latestNavigationSpan).description === DEFAULT_NAVIGATION_SPAN_NAME) {\n latestNavigationSpan.updateName(route.name);\n }\n latestNavigationSpan.setAttributes({\n 'route.name': route.name,\n 'route.key': route.key,\n // TODO: filter PII params instead of dropping them all\n // 'route.params': {},\n 'route.has_been_seen': routeHasBeenSeen,\n 'previous_route.name': previousRoute?.name,\n 'previous_route.key': previousRoute?.key,\n // TODO: filter PII params instead of dropping them all\n // 'previous_route.params': {},\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n });\n\n // Clear the timeout so the transaction does not get cancelled.\n clearStateChangeTimeout();\n\n addBreadcrumb({\n category: 'navigation',\n type: 'navigation',\n message: `Navigation to ${route.name}`,\n data: {\n from: previousRoute?.name,\n to: route.name,\n },\n });\n\n tracing?.setCurrentRoute(route.name);\n\n pushRecentRouteKey(route.key);\n latestRoute = route;\n // Clear the latest transaction as it has been handled.\n latestNavigationSpan = undefined;\n };\n\n /** Pushes a recent route key, and removes earlier routes when there is greater than the max length */\n const pushRecentRouteKey = (key: string): void => {\n recentRouteKeys.push(key);\n\n if (recentRouteKeys.length > NAVIGATION_HISTORY_MAX_SIZE) {\n recentRouteKeys = recentRouteKeys.slice(recentRouteKeys.length - NAVIGATION_HISTORY_MAX_SIZE);\n }\n };\n\n /** Cancels the latest transaction so it does not get sent to Sentry. */\n const _discardLatestTransaction = (): void => {\n if (latestNavigationSpan) {\n if (isSentrySpan(latestNavigationSpan)) {\n latestNavigationSpan['_sampled'] = false;\n }\n // TODO: What if it's not SentrySpan?\n latestNavigationSpan.end();\n latestNavigationSpan = undefined;\n }\n if (navigationProcessingSpan) {\n navigationProcessingSpan = undefined;\n }\n };\n\n const clearStateChangeTimeout = (): void => {\n if (typeof stateChangeTimeout !== 'undefined') {\n clearTimeout(stateChangeTimeout);\n stateChangeTimeout = undefined;\n }\n };\n\n return {\n name: INTEGRATION_NAME,\n afterAllSetup,\n registerNavigationContainer,\n options: {\n routeChangeTimeoutMs,\n enableTimeToInitialDisplay,\n ignoreEmptyBackNavigationTransactions,\n enableTimeToInitialDisplayForPreloadedRoutes,\n useDispatchedActionData,\n },\n };\n};\n\nexport interface NavigationRoute {\n name: string;\n key: string;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n params?: Record<string, any>;\n}\n\ninterface NavigationContainer {\n addListener: (type: string, listener: (event?: unknown) => void) => void;\n getCurrentRoute: () => NavigationRoute;\n}\n\n/**\n * Returns React Navigation integration of the given client.\n */\nexport function getReactNavigationIntegration(\n client: Client,\n): ReturnType<typeof reactNavigationIntegration> | undefined {\n return client.getIntegrationByName<ReturnType<typeof reactNavigationIntegration>>(INTEGRATION_NAME);\n}\n"]}
|
package/dist/js/tracing/span.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { generateTraceId, getActiveSpan, getClient, getCurrentScope,
|
|
1
|
+
import { debug, generateTraceId, getActiveSpan, getClient, getCurrentScope, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SentryNonRecordingSpan, SPAN_STATUS_ERROR, spanToJSON, startIdleSpan as coreStartIdleSpan, } from '@sentry/core';
|
|
2
2
|
import { AppState } from 'react-native';
|
|
3
3
|
import { isRootSpan } from '../utils/span';
|
|
4
4
|
import { adjustTransactionDuration, cancelInBackground } from './onSpanEndUtils';
|
|
@@ -11,19 +11,19 @@ export const defaultIdleOptions = {
|
|
|
11
11
|
export const startIdleNavigationSpan = (startSpanOption, { finalTimeout = defaultIdleOptions.finalTimeout, idleTimeout = defaultIdleOptions.idleTimeout, } = {}) => {
|
|
12
12
|
const client = getClient();
|
|
13
13
|
if (!client) {
|
|
14
|
-
|
|
14
|
+
debug.warn("[startIdleNavigationSpan] Can't create route change span, missing client.");
|
|
15
15
|
return undefined;
|
|
16
16
|
}
|
|
17
17
|
const activeSpan = getActiveSpan();
|
|
18
18
|
clearActiveSpanFromScope(getCurrentScope());
|
|
19
19
|
if (activeSpan && isRootSpan(activeSpan) && isSentryInteractionSpan(activeSpan)) {
|
|
20
|
-
|
|
20
|
+
debug.log(`[startIdleNavigationSpan] Canceling ${spanToJSON(activeSpan).op} transaction because of a new navigation root span.`);
|
|
21
21
|
activeSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'cancelled' });
|
|
22
22
|
activeSpan.end();
|
|
23
23
|
}
|
|
24
24
|
const finalStartSpanOptions = Object.assign(Object.assign({}, getDefaultIdleNavigationSpanOptions()), startSpanOption);
|
|
25
25
|
const idleSpan = startIdleSpan(finalStartSpanOptions, { finalTimeout, idleTimeout });
|
|
26
|
-
|
|
26
|
+
debug.log(`[startIdleNavigationSpan] Starting ${finalStartSpanOptions.op || 'unknown op'} transaction "${finalStartSpanOptions.name}" on scope`);
|
|
27
27
|
adjustTransactionDuration(client, idleSpan, finalTimeout);
|
|
28
28
|
idleSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_NAVIGATION_CUSTOM);
|
|
29
29
|
return idleSpan;
|
|
@@ -38,12 +38,12 @@ export const startIdleNavigationSpan = (startSpanOption, { finalTimeout = defaul
|
|
|
38
38
|
export const startIdleSpan = (startSpanOption, { finalTimeout, idleTimeout }) => {
|
|
39
39
|
const client = getClient();
|
|
40
40
|
if (!client) {
|
|
41
|
-
|
|
41
|
+
debug.warn("[startIdleSpan] Can't create idle span, missing client.");
|
|
42
42
|
return new SentryNonRecordingSpan();
|
|
43
43
|
}
|
|
44
44
|
const currentAppState = AppState.currentState;
|
|
45
45
|
if (currentAppState === 'background') {
|
|
46
|
-
|
|
46
|
+
debug.log(`[startIdleSpan] App is already in background, not starting span for ${startSpanOption.name}`);
|
|
47
47
|
return new SentryNonRecordingSpan();
|
|
48
48
|
}
|
|
49
49
|
getCurrentScope().setPropagationContext({ traceId: generateTraceId(), sampleRand: Math.random() });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"span.js","sourceRoot":"","sources":["../../../src/js/tracing/span.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,aAAa,EACb,SAAS,EACT,eAAe,EACf,
|
|
1
|
+
{"version":3,"file":"span.js","sourceRoot":"","sources":["../../../src/js/tracing/span.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Client, Scope, Span, SpanJSON, StartSpanOptions } from '@sentry/core';\nimport {\n debug,\n generateTraceId,\n getActiveSpan,\n getClient,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SentryNonRecordingSpan,\n SPAN_STATUS_ERROR,\n spanToJSON,\n startIdleSpan as coreStartIdleSpan,\n} from '@sentry/core';\nimport { AppState } from 'react-native';\nimport { isRootSpan } from '../utils/span';\nimport { adjustTransactionDuration, cancelInBackground } from './onSpanEndUtils';\nimport {\n SPAN_ORIGIN_AUTO_INTERACTION,\n SPAN_ORIGIN_AUTO_NAVIGATION_CUSTOM,\n SPAN_ORIGIN_MANUAL_INTERACTION,\n} from './origin';\n\nexport const DEFAULT_NAVIGATION_SPAN_NAME = 'Route Change';\n\nexport const defaultIdleOptions: {\n /**\n * The time that has to pass without any span being created.\n * If this time is exceeded, the idle span will finish.\n *\n * @default 1_000 (ms)\n */\n finalTimeout: number;\n\n /**\n * The max. time an idle span may run.\n * If this time is exceeded, the idle span will finish no matter what.\n *\n * @default 60_0000 (ms)\n */\n idleTimeout: number;\n} = {\n idleTimeout: 1_000,\n finalTimeout: 60_0000,\n};\n\nexport const startIdleNavigationSpan = (\n startSpanOption: StartSpanOptions,\n {\n finalTimeout = defaultIdleOptions.finalTimeout,\n idleTimeout = defaultIdleOptions.idleTimeout,\n }: Partial<typeof defaultIdleOptions> = {},\n): Span | undefined => {\n const client = getClient();\n if (!client) {\n debug.warn(\"[startIdleNavigationSpan] Can't create route change span, missing client.\");\n return undefined;\n }\n\n const activeSpan = getActiveSpan();\n clearActiveSpanFromScope(getCurrentScope());\n if (activeSpan && isRootSpan(activeSpan) && isSentryInteractionSpan(activeSpan)) {\n debug.log(\n `[startIdleNavigationSpan] Canceling ${\n spanToJSON(activeSpan).op\n } transaction because of a new navigation root span.`,\n );\n activeSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'cancelled' });\n activeSpan.end();\n }\n\n const finalStartSpanOptions = {\n ...getDefaultIdleNavigationSpanOptions(),\n ...startSpanOption,\n };\n\n const idleSpan = startIdleSpan(finalStartSpanOptions, { finalTimeout, idleTimeout });\n debug.log(\n `[startIdleNavigationSpan] Starting ${finalStartSpanOptions.op || 'unknown op'} transaction \"${\n finalStartSpanOptions.name\n }\" on scope`,\n );\n\n adjustTransactionDuration(client, idleSpan, finalTimeout);\n\n idleSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_NAVIGATION_CUSTOM);\n return idleSpan;\n};\n\n/**\n * Starts an idle span from `@sentry/core` with React Native application\n * context awareness.\n *\n * - Span will be started with new propagation context.\n * - Span will be canceled if the app goes to background.\n */\nexport const startIdleSpan = (\n startSpanOption: StartSpanOptions,\n { finalTimeout, idleTimeout }: { finalTimeout: number | undefined; idleTimeout: number | undefined },\n): Span => {\n const client = getClient();\n if (!client) {\n debug.warn(\"[startIdleSpan] Can't create idle span, missing client.\");\n return new SentryNonRecordingSpan();\n }\n\n const currentAppState = AppState.currentState;\n if (currentAppState === 'background') {\n debug.log(`[startIdleSpan] App is already in background, not starting span for ${startSpanOption.name}`);\n return new SentryNonRecordingSpan();\n }\n\n getCurrentScope().setPropagationContext({ traceId: generateTraceId(), sampleRand: Math.random() });\n\n const span = coreStartIdleSpan(startSpanOption, { finalTimeout, idleTimeout });\n cancelInBackground(client, span);\n return span;\n};\n\n/**\n * Returns the default options for the idle navigation span.\n */\nexport function getDefaultIdleNavigationSpanOptions(): StartSpanOptions {\n return {\n name: DEFAULT_NAVIGATION_SPAN_NAME,\n op: 'navigation',\n forceTransaction: true,\n scope: getCurrentScope(),\n };\n}\n\n/**\n * Checks if the span is a Sentry User Interaction span.\n */\nexport function isSentryInteractionSpan(span: Span): boolean {\n return [SPAN_ORIGIN_AUTO_INTERACTION, SPAN_ORIGIN_MANUAL_INTERACTION].includes(spanToJSON(span).origin || '');\n}\n\nexport const SCOPE_SPAN_FIELD = '_sentrySpan';\n\nexport type ScopeWithMaybeSpan = Scope & {\n [SCOPE_SPAN_FIELD]?: Span;\n};\n\n/**\n * Removes the active span from the scope.\n */\nexport function clearActiveSpanFromScope(scope: ScopeWithMaybeSpan): void {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete scope[SCOPE_SPAN_FIELD];\n}\n\n/**\n * Ensures that all created spans have an operation name.\n */\nexport function addDefaultOpForSpanFrom(client: Client): void {\n client.on('spanStart', (span: Span) => {\n if (!spanToJSON(span).op) {\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'default');\n }\n });\n}\n\nexport const SPAN_THREAD_NAME = 'thread.name';\nexport const SPAN_THREAD_NAME_MAIN = 'main';\nexport const SPAN_THREAD_NAME_JAVASCRIPT = 'javascript';\n\n/**\n * Adds Javascript thread info to spans.\n * Ref: https://reactnative.dev/architecture/threading-model\n */\nexport function addThreadInfoToSpan(client: Client): void {\n client.on('spanStart', (span: Span) => {\n if (!spanToJSON(span).data?.[SPAN_THREAD_NAME]) {\n span.setAttribute(SPAN_THREAD_NAME, SPAN_THREAD_NAME_JAVASCRIPT);\n }\n });\n}\n\n/**\n * Sets the Main thread info to the span.\n */\nexport function setMainThreadInfo(spanJSON: SpanJSON): SpanJSON {\n spanJSON.data = spanJSON.data || {};\n spanJSON.data[SPAN_THREAD_NAME] = SPAN_THREAD_NAME_MAIN;\n return spanJSON;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timetodisplay.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/timetodisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAC,gBAAgB,EAAG,MAAM,cAAc,CAAC;AAE3D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"timetodisplay.d.ts","sourceRoot":"","sources":["../../../src/js/tracing/timetodisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAC,gBAAgB,EAAG,MAAM,cAAc,CAAC;AAE3D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B;;GAEG;AACH,eAAO,MAAM,yBAAyB,qBAA4B,CAAC;AAOnE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAQlF;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAI/E;AAoBD;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,CAAC,EAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,MAAM,CAAC,GAAG;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B,GACA,IAAI,GAAG,SAAS,CAgClB;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,GAAE,IAAI,CAAC,gBAAgB,EAAE,IAAI,GAAG,MAAM,CAAC,GAAG;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAG7B,GACA,IAAI,GAAG,SAAS,CAqDlB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,qBAAqB,EAAE,MAAM,EAC7B,EACE,UAA4B,EAC5B,IAAsC,GACvC,GAAE;IACD,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB;;OAEG;IACH,IAAI,CAAC,EAAE,IAAI,CAAC;CACR,GAAG,IAAI,CAgCd;AA6CD;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,cAAc,GACf,EAAE;IACD;;OAEG;IACH,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAA;CAC/C,GAAG,KAAK,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAE1C;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,cAAc,GACf,EAAE;IACD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAA;CAC/C,GAAG,KAAK,CAAC,aAAa,CAAC,kBAAkB,CAAC,CAE1C"}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { fill, getActiveSpan, getSpanDescendants,
|
|
1
|
+
import { debug, fill, getActiveSpan, getSpanDescendants, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_STATUS_ERROR, SPAN_STATUS_OK, spanToJSON, startInactiveSpan } from '@sentry/core';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { isTurboModuleEnabled } from '../utils/environment';
|
|
5
4
|
import { SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY } from './origin';
|
|
6
|
-
import { getRNSentryOnDrawReporter
|
|
5
|
+
import { getRNSentryOnDrawReporter } from './timetodisplaynative';
|
|
7
6
|
import { setSpanDurationAsMeasurement, setSpanDurationAsMeasurementOnSpan } from './utils';
|
|
8
|
-
let nativeComponentMissingLogged = false;
|
|
9
7
|
/**
|
|
10
8
|
* Flags of active spans with manual initial display.
|
|
11
9
|
*/
|
|
@@ -43,14 +41,6 @@ export function TimeToFullDisplay(props) {
|
|
|
43
41
|
}
|
|
44
42
|
function TimeToDisplay(props) {
|
|
45
43
|
const RNSentryOnDrawReporter = getRNSentryOnDrawReporter();
|
|
46
|
-
const isNewArchitecture = isTurboModuleEnabled();
|
|
47
|
-
if (__DEV__ && (isNewArchitecture || (!nativeComponentExists && !nativeComponentMissingLogged))) {
|
|
48
|
-
nativeComponentMissingLogged = true;
|
|
49
|
-
// Using setTimeout with a delay of 0 milliseconds to defer execution and avoid printing the React stack trace.
|
|
50
|
-
setTimeout(() => {
|
|
51
|
-
logger.warn('TimeToInitialDisplay and TimeToFullDisplay are not supported on the web, Expo Go and New Architecture. Run native build or report an issue at https://github.com/getsentry/sentry-react-native');
|
|
52
|
-
}, 0);
|
|
53
|
-
}
|
|
54
44
|
return (React.createElement(React.Fragment, null,
|
|
55
45
|
React.createElement(RNSentryOnDrawReporter, { initialDisplay: props.initialDisplay, fullDisplay: props.fullDisplay, parentSpanId: props.parentSpanId }),
|
|
56
46
|
props.children));
|
|
@@ -65,12 +55,12 @@ function TimeToDisplay(props) {
|
|
|
65
55
|
export function startTimeToInitialDisplaySpan(options) {
|
|
66
56
|
const activeSpan = getActiveSpan();
|
|
67
57
|
if (!activeSpan) {
|
|
68
|
-
|
|
58
|
+
debug.warn('[TimeToDisplay] No active span found to attach ui.load.initial_display to.');
|
|
69
59
|
return undefined;
|
|
70
60
|
}
|
|
71
61
|
const existingSpan = getSpanDescendants(activeSpan).find((span) => spanToJSON(span).op === 'ui.load.initial_display');
|
|
72
62
|
if (existingSpan) {
|
|
73
|
-
|
|
63
|
+
debug.log('[TimeToDisplay] Found existing ui.load.initial_display span.');
|
|
74
64
|
return existingSpan;
|
|
75
65
|
}
|
|
76
66
|
const initialDisplaySpan = startInactiveSpan(Object.assign({ op: 'ui.load.initial_display', name: 'Time To Initial Display', startTime: spanToJSON(activeSpan).start_timestamp }, options));
|
|
@@ -98,18 +88,18 @@ export function startTimeToFullDisplaySpan(options = {
|
|
|
98
88
|
}) {
|
|
99
89
|
const activeSpan = getActiveSpan();
|
|
100
90
|
if (!activeSpan) {
|
|
101
|
-
|
|
91
|
+
debug.warn('[TimeToDisplay] No active span found to attach ui.load.full_display to.');
|
|
102
92
|
return undefined;
|
|
103
93
|
}
|
|
104
94
|
const descendantSpans = getSpanDescendants(activeSpan);
|
|
105
95
|
const initialDisplaySpan = descendantSpans.find((span) => spanToJSON(span).op === 'ui.load.initial_display');
|
|
106
96
|
if (!initialDisplaySpan) {
|
|
107
|
-
|
|
97
|
+
debug.warn('[TimeToDisplay] No initial display span found to attach ui.load.full_display to.');
|
|
108
98
|
return undefined;
|
|
109
99
|
}
|
|
110
100
|
const existingSpan = descendantSpans.find((span) => spanToJSON(span).op === 'ui.load.full_display');
|
|
111
101
|
if (existingSpan) {
|
|
112
|
-
|
|
102
|
+
debug.log('[TimeToDisplay] Found existing ui.load.full_display span.');
|
|
113
103
|
return existingSpan;
|
|
114
104
|
}
|
|
115
105
|
const fullDisplaySpan = startInactiveSpan(Object.assign({ op: 'ui.load.full_display', name: 'Time To Full Display', startTime: spanToJSON(initialDisplaySpan).start_timestamp }, options));
|
|
@@ -123,7 +113,7 @@ export function startTimeToFullDisplaySpan(options = {
|
|
|
123
113
|
fullDisplaySpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'deadline_exceeded' });
|
|
124
114
|
fullDisplaySpan.end(spanToJSON(initialDisplaySpan).timestamp);
|
|
125
115
|
setSpanDurationAsMeasurement('time_to_full_display', fullDisplaySpan);
|
|
126
|
-
|
|
116
|
+
debug.warn('[TimeToDisplay] Full display span deadline_exceeded.');
|
|
127
117
|
}, options.timeoutMs);
|
|
128
118
|
fill(fullDisplaySpan, 'end', (originalEnd) => (endTimestamp) => {
|
|
129
119
|
clearTimeout(timeout);
|
|
@@ -142,27 +132,27 @@ export function startTimeToFullDisplaySpan(options = {
|
|
|
142
132
|
*/
|
|
143
133
|
export function updateInitialDisplaySpan(frameTimestampSeconds, { activeSpan = getActiveSpan(), span = startTimeToInitialDisplaySpan(), } = {}) {
|
|
144
134
|
if (!span) {
|
|
145
|
-
|
|
135
|
+
debug.warn('[TimeToDisplay] No span found or created, possibly performance is disabled.');
|
|
146
136
|
return;
|
|
147
137
|
}
|
|
148
138
|
if (!activeSpan) {
|
|
149
|
-
|
|
139
|
+
debug.warn('[TimeToDisplay] No active span found to attach ui.load.initial_display to.');
|
|
150
140
|
return;
|
|
151
141
|
}
|
|
152
142
|
if (spanToJSON(span).parent_span_id !== spanToJSON(activeSpan).span_id) {
|
|
153
|
-
|
|
143
|
+
debug.warn('[TimeToDisplay] Initial display span is not a child of current active span.');
|
|
154
144
|
return;
|
|
155
145
|
}
|
|
156
146
|
if (spanToJSON(span).timestamp) {
|
|
157
|
-
|
|
147
|
+
debug.warn(`[TimeToDisplay] ${spanToJSON(span).description} span already ended.`);
|
|
158
148
|
return;
|
|
159
149
|
}
|
|
160
150
|
span.end(frameTimestampSeconds);
|
|
161
151
|
span.setStatus({ code: SPAN_STATUS_OK });
|
|
162
|
-
|
|
152
|
+
debug.log(`[TimeToDisplay] ${spanToJSON(span).description} span updated with end timestamp.`);
|
|
163
153
|
if (fullDisplayBeforeInitialDisplay.has(activeSpan)) {
|
|
164
154
|
fullDisplayBeforeInitialDisplay.delete(activeSpan);
|
|
165
|
-
|
|
155
|
+
debug.log(`[TimeToDisplay] Updating full display with initial display (${span.spanContext().spanId}) end.`);
|
|
166
156
|
updateFullDisplaySpan(frameTimestampSeconds, span);
|
|
167
157
|
}
|
|
168
158
|
setSpanDurationAsMeasurementOnSpan('time_to_initial_display', span, activeSpan);
|
|
@@ -170,7 +160,7 @@ export function updateInitialDisplaySpan(frameTimestampSeconds, { activeSpan = g
|
|
|
170
160
|
function updateFullDisplaySpan(frameTimestampSeconds, passedInitialDisplaySpan) {
|
|
171
161
|
const activeSpan = getActiveSpan();
|
|
172
162
|
if (!activeSpan) {
|
|
173
|
-
|
|
163
|
+
debug.warn('[TimeToDisplay] No active span found to update ui.load.full_display in.');
|
|
174
164
|
return;
|
|
175
165
|
}
|
|
176
166
|
const existingInitialDisplaySpan = passedInitialDisplaySpan
|
|
@@ -178,30 +168,30 @@ function updateFullDisplaySpan(frameTimestampSeconds, passedInitialDisplaySpan)
|
|
|
178
168
|
const initialDisplayEndTimestamp = existingInitialDisplaySpan && spanToJSON(existingInitialDisplaySpan).timestamp;
|
|
179
169
|
if (!initialDisplayEndTimestamp) {
|
|
180
170
|
fullDisplayBeforeInitialDisplay.set(activeSpan, true);
|
|
181
|
-
|
|
171
|
+
debug.warn(`[TimeToDisplay] Full display called before initial display for active span (${activeSpan.spanContext().spanId}).`);
|
|
182
172
|
return;
|
|
183
173
|
}
|
|
184
174
|
const span = startTimeToFullDisplaySpan({
|
|
185
175
|
isAutoInstrumented: true,
|
|
186
176
|
});
|
|
187
177
|
if (!span) {
|
|
188
|
-
|
|
178
|
+
debug.warn('[TimeToDisplay] No TimeToFullDisplay span found or created, possibly performance is disabled.');
|
|
189
179
|
return;
|
|
190
180
|
}
|
|
191
181
|
const spanJSON = spanToJSON(span);
|
|
192
182
|
if (spanJSON.timestamp) {
|
|
193
|
-
|
|
183
|
+
debug.warn(`[TimeToDisplay] ${spanJSON.description} (${spanJSON.span_id}) span already ended.`);
|
|
194
184
|
return;
|
|
195
185
|
}
|
|
196
186
|
if (initialDisplayEndTimestamp > frameTimestampSeconds) {
|
|
197
|
-
|
|
187
|
+
debug.warn('[TimeToDisplay] Using initial display end. Full display end frame timestamp is before initial display end.');
|
|
198
188
|
span.end(initialDisplayEndTimestamp);
|
|
199
189
|
}
|
|
200
190
|
else {
|
|
201
191
|
span.end(frameTimestampSeconds);
|
|
202
192
|
}
|
|
203
193
|
span.setStatus({ code: SPAN_STATUS_OK });
|
|
204
|
-
|
|
194
|
+
debug.log(`[TimeToDisplay] ${spanJSON.description} (${spanJSON.span_id}) span updated with end timestamp.`);
|
|
205
195
|
setSpanDurationAsMeasurement('time_to_full_display', span);
|
|
206
196
|
}
|
|
207
197
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timetodisplay.js","sourceRoot":"","sources":["../../../src/js/tracing/timetodisplay.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { Span,StartSpanOptions } from '@sentry/core';\nimport { fill, getActiveSpan, getSpanDescendants, logger, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_STATUS_ERROR, SPAN_STATUS_OK, spanToJSON, startInactiveSpan } from '@sentry/core';\nimport * as React from 'react';\nimport { useState } from 'react';\nimport { isTurboModuleEnabled } from '../utils/environment';\nimport { SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY } from './origin';\nimport { getRNSentryOnDrawReporter, nativeComponentExists } from './timetodisplaynative';\nimport { setSpanDurationAsMeasurement, setSpanDurationAsMeasurementOnSpan } from './utils';\n\nlet nativeComponentMissingLogged = false;\n\n/**\n * Flags of active spans with manual initial display.\n */\nexport const manualInitialDisplaySpans = new WeakMap<Span, true>();\n\n/**\n * Flag full display called before initial display for an active span.\n */\nconst fullDisplayBeforeInitialDisplay = new WeakMap<Span, true>();\n\nexport type TimeToDisplayProps = {\n children?: React.ReactNode;\n record?: boolean;\n};\n\n/**\n * Component to measure time to initial display.\n *\n * The initial display is recorded when the component prop `record` is true.\n *\n * <TimeToInitialDisplay record />\n */\nexport function TimeToInitialDisplay(props: TimeToDisplayProps): React.ReactElement {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n manualInitialDisplaySpans.set(activeSpan, true);\n }\n\n const parentSpanId = activeSpan && spanToJSON(activeSpan).span_id;\n return <TimeToDisplay initialDisplay={props.record} parentSpanId={parentSpanId}>{props.children}</TimeToDisplay>;\n}\n\n/**\n * Component to measure time to full display.\n *\n * The initial display is recorded when the component prop `record` is true.\n *\n * <TimeToInitialDisplay record />\n */\nexport function TimeToFullDisplay(props: TimeToDisplayProps): React.ReactElement {\n const activeSpan = getActiveSpan();\n const parentSpanId = activeSpan && spanToJSON(activeSpan).span_id;\n return <TimeToDisplay fullDisplay={props.record} parentSpanId={parentSpanId}>{props.children}</TimeToDisplay>;\n}\n\nfunction TimeToDisplay(props: {\n children?: React.ReactNode;\n initialDisplay?: boolean;\n fullDisplay?: boolean;\n parentSpanId?: string;\n}): React.ReactElement {\n const RNSentryOnDrawReporter = getRNSentryOnDrawReporter();\n const isNewArchitecture = isTurboModuleEnabled();\n\n if (__DEV__ && (isNewArchitecture || (!nativeComponentExists && !nativeComponentMissingLogged))){\n nativeComponentMissingLogged = true;\n // Using setTimeout with a delay of 0 milliseconds to defer execution and avoid printing the React stack trace.\n setTimeout(() => {\n logger.warn(\n 'TimeToInitialDisplay and TimeToFullDisplay are not supported on the web, Expo Go and New Architecture. Run native build or report an issue at https://github.com/getsentry/sentry-react-native');\n }, 0);\n }\n\n return (\n <>\n <RNSentryOnDrawReporter\n initialDisplay={props.initialDisplay}\n fullDisplay={props.fullDisplay}\n parentSpanId={props.parentSpanId} />\n {props.children}\n </>\n );\n}\n\n/**\n * Starts a new span for the initial display.\n *\n * Returns current span if already exists in the currently active span.\n *\n * @deprecated Use `<TimeToInitialDisplay record={boolean}/>` component instead.\n */\nexport function startTimeToInitialDisplaySpan(\n options?: Omit<StartSpanOptions, 'op' | 'name'> & {\n name?: string;\n isAutoInstrumented?: boolean\n },\n): Span | undefined {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n logger.warn('[TimeToDisplay] No active span found to attach ui.load.initial_display to.');\n return undefined;\n }\n\n const existingSpan = getSpanDescendants(activeSpan).find((span) => spanToJSON(span).op === 'ui.load.initial_display');\n if (existingSpan) {\n logger.debug('[TimeToDisplay] Found existing ui.load.initial_display span.');\n return existingSpan\n }\n\n const initialDisplaySpan = startInactiveSpan({\n op: 'ui.load.initial_display',\n name: 'Time To Initial Display',\n startTime: spanToJSON(activeSpan).start_timestamp,\n ...options,\n });\n\n if (!initialDisplaySpan) {\n return undefined;\n }\n\n if (options?.isAutoInstrumented) {\n initialDisplaySpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY);\n } else {\n manualInitialDisplaySpans.set(activeSpan, true);\n initialDisplaySpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY);\n }\n\n return initialDisplaySpan;\n}\n\n/**\n * Starts a new span for the full display.\n *\n * Returns current span if already exists in the currently active span.\n *\n * @deprecated Use `<TimeToFullDisplay record={boolean}/>` component instead.\n */\nexport function startTimeToFullDisplaySpan(\n options: Omit<StartSpanOptions, 'op' | 'name'> & {\n name?: string,\n timeoutMs?: number,\n isAutoInstrumented?: boolean\n } = {\n timeoutMs: 30_000,\n },\n): Span | undefined {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n logger.warn('[TimeToDisplay] No active span found to attach ui.load.full_display to.');\n return undefined;\n }\n\n const descendantSpans = getSpanDescendants(activeSpan);\n\n const initialDisplaySpan = descendantSpans.find((span) => spanToJSON(span).op === 'ui.load.initial_display');\n if (!initialDisplaySpan) {\n logger.warn('[TimeToDisplay] No initial display span found to attach ui.load.full_display to.');\n return undefined;\n }\n\n const existingSpan = descendantSpans.find((span) => spanToJSON(span).op === 'ui.load.full_display');\n if (existingSpan) {\n logger.debug('[TimeToDisplay] Found existing ui.load.full_display span.');\n return existingSpan;\n }\n\n const fullDisplaySpan = startInactiveSpan({\n op: 'ui.load.full_display',\n name: 'Time To Full Display',\n startTime: spanToJSON(initialDisplaySpan).start_timestamp,\n ...options,\n });\n if (!fullDisplaySpan) {\n return undefined;\n }\n\n const timeout = setTimeout(() => {\n if (spanToJSON(fullDisplaySpan).timestamp) {\n return;\n }\n fullDisplaySpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'deadline_exceeded' });\n fullDisplaySpan.end(spanToJSON(initialDisplaySpan).timestamp);\n setSpanDurationAsMeasurement('time_to_full_display', fullDisplaySpan);\n logger.warn('[TimeToDisplay] Full display span deadline_exceeded.');\n }, options.timeoutMs);\n\n fill(fullDisplaySpan, 'end', (originalEnd: Span['end']) => (endTimestamp?: Parameters<Span['end']>[0]) => {\n clearTimeout(timeout);\n originalEnd.call(fullDisplaySpan, endTimestamp);\n });\n\n if (options?.isAutoInstrumented) {\n fullDisplaySpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY);\n } else {\n fullDisplaySpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY);\n }\n\n return fullDisplaySpan;\n}\n\n/**\n *\n */\nexport function updateInitialDisplaySpan(\n frameTimestampSeconds: number,\n {\n activeSpan = getActiveSpan(),\n span = startTimeToInitialDisplaySpan(),\n }: {\n activeSpan?: Span;\n /**\n * Time to initial display span to update.\n */\n span?: Span;\n } = {}): void {\n if (!span) {\n logger.warn('[TimeToDisplay] No span found or created, possibly performance is disabled.');\n return;\n }\n\n if (!activeSpan) {\n logger.warn('[TimeToDisplay] No active span found to attach ui.load.initial_display to.');\n return;\n }\n\n if (spanToJSON(span).parent_span_id !== spanToJSON(activeSpan).span_id) {\n logger.warn('[TimeToDisplay] Initial display span is not a child of current active span.');\n return;\n }\n\n if (spanToJSON(span).timestamp) {\n logger.warn(`[TimeToDisplay] ${spanToJSON(span).description} span already ended.`);\n return;\n }\n\n span.end(frameTimestampSeconds);\n span.setStatus({ code: SPAN_STATUS_OK });\n logger.debug(`[TimeToDisplay] ${spanToJSON(span).description} span updated with end timestamp.`);\n\n if (fullDisplayBeforeInitialDisplay.has(activeSpan)) {\n fullDisplayBeforeInitialDisplay.delete(activeSpan);\n logger.debug(`[TimeToDisplay] Updating full display with initial display (${span.spanContext().spanId}) end.`);\n updateFullDisplaySpan(frameTimestampSeconds, span);\n }\n\n setSpanDurationAsMeasurementOnSpan('time_to_initial_display', span, activeSpan);\n}\n\nfunction updateFullDisplaySpan(frameTimestampSeconds: number, passedInitialDisplaySpan?: Span): void {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n logger.warn('[TimeToDisplay] No active span found to update ui.load.full_display in.');\n return;\n }\n\n const existingInitialDisplaySpan = passedInitialDisplaySpan\n || getSpanDescendants(activeSpan).find((span) => spanToJSON(span).op === 'ui.load.initial_display');\n const initialDisplayEndTimestamp = existingInitialDisplaySpan && spanToJSON(existingInitialDisplaySpan).timestamp;\n if (!initialDisplayEndTimestamp) {\n fullDisplayBeforeInitialDisplay.set(activeSpan, true);\n logger.warn(`[TimeToDisplay] Full display called before initial display for active span (${activeSpan.spanContext().spanId}).`);\n return;\n }\n\n const span = startTimeToFullDisplaySpan({\n isAutoInstrumented: true,\n });\n if (!span) {\n logger.warn('[TimeToDisplay] No TimeToFullDisplay span found or created, possibly performance is disabled.');\n return;\n }\n\n const spanJSON = spanToJSON(span);\n if (spanJSON.timestamp) {\n logger.warn(`[TimeToDisplay] ${spanJSON.description} (${spanJSON.span_id}) span already ended.`);\n return;\n }\n\n if (initialDisplayEndTimestamp > frameTimestampSeconds) {\n logger.warn('[TimeToDisplay] Using initial display end. Full display end frame timestamp is before initial display end.');\n span.end(initialDisplayEndTimestamp);\n } else {\n span.end(frameTimestampSeconds);\n }\n\n span.setStatus({ code: SPAN_STATUS_OK });\n logger.debug(`[TimeToDisplay] ${spanJSON.description} (${spanJSON.span_id}) span updated with end timestamp.`);\n\n setSpanDurationAsMeasurement('time_to_full_display', span);\n}\n\n/**\n * Creates a new TimeToFullDisplay component which triggers the full display recording every time the component is focused.\n */\nexport function createTimeToFullDisplay({\n useFocusEffect,\n}: {\n /**\n * `@react-navigation/native` useFocusEffect hook.\n */\n useFocusEffect: (callback: () => void) => void\n}): React.ComponentType<TimeToDisplayProps> {\n return createTimeToDisplay({ useFocusEffect, Component: TimeToFullDisplay });\n}\n\n/**\n * Creates a new TimeToInitialDisplay component which triggers the initial display recording every time the component is focused.\n */\nexport function createTimeToInitialDisplay({\n useFocusEffect,\n}: {\n useFocusEffect: (callback: () => void) => void\n}): React.ComponentType<TimeToDisplayProps> {\n return createTimeToDisplay({ useFocusEffect, Component: TimeToInitialDisplay });\n}\n\nfunction createTimeToDisplay({\n useFocusEffect,\n Component,\n}: {\n /**\n * `@react-navigation/native` useFocusEffect hook.\n */\n useFocusEffect: (callback: () => void) => void;\n Component: typeof TimeToFullDisplay | typeof TimeToInitialDisplay;\n}): React.ComponentType<TimeToDisplayProps> {\n const TimeToDisplayWrapper = (props: TimeToDisplayProps): React.ReactElement => {\n const [focused, setFocused] = useState(false);\n\n useFocusEffect(() => {\n setFocused(true);\n return () => {\n setFocused(false);\n };\n });\n\n return <Component {...props} record={focused && props.record} />;\n };\n\n TimeToDisplayWrapper.displayName = 'TimeToDisplayWrapper';\n return TimeToDisplayWrapper;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"timetodisplay.js","sourceRoot":"","sources":["../../../src/js/tracing/timetodisplay.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { Span,StartSpanOptions } from '@sentry/core';\nimport { debug, fill, getActiveSpan, getSpanDescendants, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_STATUS_ERROR, SPAN_STATUS_OK, spanToJSON, startInactiveSpan } from '@sentry/core';\nimport * as React from 'react';\nimport { useState } from 'react';\nimport { SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY } from './origin';\nimport { getRNSentryOnDrawReporter } from './timetodisplaynative';\nimport { setSpanDurationAsMeasurement, setSpanDurationAsMeasurementOnSpan } from './utils';\n\n/**\n * Flags of active spans with manual initial display.\n */\nexport const manualInitialDisplaySpans = new WeakMap<Span, true>();\n\n/**\n * Flag full display called before initial display for an active span.\n */\nconst fullDisplayBeforeInitialDisplay = new WeakMap<Span, true>();\n\nexport type TimeToDisplayProps = {\n children?: React.ReactNode;\n record?: boolean;\n};\n\n/**\n * Component to measure time to initial display.\n *\n * The initial display is recorded when the component prop `record` is true.\n *\n * <TimeToInitialDisplay record />\n */\nexport function TimeToInitialDisplay(props: TimeToDisplayProps): React.ReactElement {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n manualInitialDisplaySpans.set(activeSpan, true);\n }\n\n const parentSpanId = activeSpan && spanToJSON(activeSpan).span_id;\n return <TimeToDisplay initialDisplay={props.record} parentSpanId={parentSpanId}>{props.children}</TimeToDisplay>;\n}\n\n/**\n * Component to measure time to full display.\n *\n * The initial display is recorded when the component prop `record` is true.\n *\n * <TimeToInitialDisplay record />\n */\nexport function TimeToFullDisplay(props: TimeToDisplayProps): React.ReactElement {\n const activeSpan = getActiveSpan();\n const parentSpanId = activeSpan && spanToJSON(activeSpan).span_id;\n return <TimeToDisplay fullDisplay={props.record} parentSpanId={parentSpanId}>{props.children}</TimeToDisplay>;\n}\n\nfunction TimeToDisplay(props: {\n children?: React.ReactNode;\n initialDisplay?: boolean;\n fullDisplay?: boolean;\n parentSpanId?: string;\n}): React.ReactElement {\n const RNSentryOnDrawReporter = getRNSentryOnDrawReporter();\n return (\n <>\n <RNSentryOnDrawReporter\n initialDisplay={props.initialDisplay}\n fullDisplay={props.fullDisplay}\n parentSpanId={props.parentSpanId} />\n {props.children}\n </>\n );\n}\n\n/**\n * Starts a new span for the initial display.\n *\n * Returns current span if already exists in the currently active span.\n *\n * @deprecated Use `<TimeToInitialDisplay record={boolean}/>` component instead.\n */\nexport function startTimeToInitialDisplaySpan(\n options?: Omit<StartSpanOptions, 'op' | 'name'> & {\n name?: string;\n isAutoInstrumented?: boolean\n },\n): Span | undefined {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n debug.warn('[TimeToDisplay] No active span found to attach ui.load.initial_display to.');\n return undefined;\n }\n\n const existingSpan = getSpanDescendants(activeSpan).find((span) => spanToJSON(span).op === 'ui.load.initial_display');\n if (existingSpan) {\n debug.log('[TimeToDisplay] Found existing ui.load.initial_display span.');\n return existingSpan\n }\n\n const initialDisplaySpan = startInactiveSpan({\n op: 'ui.load.initial_display',\n name: 'Time To Initial Display',\n startTime: spanToJSON(activeSpan).start_timestamp,\n ...options,\n });\n\n if (!initialDisplaySpan) {\n return undefined;\n }\n\n if (options?.isAutoInstrumented) {\n initialDisplaySpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY);\n } else {\n manualInitialDisplaySpans.set(activeSpan, true);\n initialDisplaySpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY);\n }\n\n return initialDisplaySpan;\n}\n\n/**\n * Starts a new span for the full display.\n *\n * Returns current span if already exists in the currently active span.\n *\n * @deprecated Use `<TimeToFullDisplay record={boolean}/>` component instead.\n */\nexport function startTimeToFullDisplaySpan(\n options: Omit<StartSpanOptions, 'op' | 'name'> & {\n name?: string,\n timeoutMs?: number,\n isAutoInstrumented?: boolean\n } = {\n timeoutMs: 30_000,\n },\n): Span | undefined {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n debug.warn('[TimeToDisplay] No active span found to attach ui.load.full_display to.');\n return undefined;\n }\n\n const descendantSpans = getSpanDescendants(activeSpan);\n\n const initialDisplaySpan = descendantSpans.find((span) => spanToJSON(span).op === 'ui.load.initial_display');\n if (!initialDisplaySpan) {\n debug.warn('[TimeToDisplay] No initial display span found to attach ui.load.full_display to.');\n return undefined;\n }\n\n const existingSpan = descendantSpans.find((span) => spanToJSON(span).op === 'ui.load.full_display');\n if (existingSpan) {\n debug.log('[TimeToDisplay] Found existing ui.load.full_display span.');\n return existingSpan;\n }\n\n const fullDisplaySpan = startInactiveSpan({\n op: 'ui.load.full_display',\n name: 'Time To Full Display',\n startTime: spanToJSON(initialDisplaySpan).start_timestamp,\n ...options,\n });\n if (!fullDisplaySpan) {\n return undefined;\n }\n\n const timeout = setTimeout(() => {\n if (spanToJSON(fullDisplaySpan).timestamp) {\n return;\n }\n fullDisplaySpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'deadline_exceeded' });\n fullDisplaySpan.end(spanToJSON(initialDisplaySpan).timestamp);\n setSpanDurationAsMeasurement('time_to_full_display', fullDisplaySpan);\n debug.warn('[TimeToDisplay] Full display span deadline_exceeded.');\n }, options.timeoutMs);\n\n fill(fullDisplaySpan, 'end', (originalEnd: Span['end']) => (endTimestamp?: Parameters<Span['end']>[0]) => {\n clearTimeout(timeout);\n originalEnd.call(fullDisplaySpan, endTimestamp);\n });\n\n if (options?.isAutoInstrumented) {\n fullDisplaySpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY);\n } else {\n fullDisplaySpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY);\n }\n\n return fullDisplaySpan;\n}\n\n/**\n *\n */\nexport function updateInitialDisplaySpan(\n frameTimestampSeconds: number,\n {\n activeSpan = getActiveSpan(),\n span = startTimeToInitialDisplaySpan(),\n }: {\n activeSpan?: Span;\n /**\n * Time to initial display span to update.\n */\n span?: Span;\n } = {}): void {\n if (!span) {\n debug.warn('[TimeToDisplay] No span found or created, possibly performance is disabled.');\n return;\n }\n\n if (!activeSpan) {\n debug.warn('[TimeToDisplay] No active span found to attach ui.load.initial_display to.');\n return;\n }\n\n if (spanToJSON(span).parent_span_id !== spanToJSON(activeSpan).span_id) {\n debug.warn('[TimeToDisplay] Initial display span is not a child of current active span.');\n return;\n }\n\n if (spanToJSON(span).timestamp) {\n debug.warn(`[TimeToDisplay] ${spanToJSON(span).description} span already ended.`);\n return;\n }\n\n span.end(frameTimestampSeconds);\n span.setStatus({ code: SPAN_STATUS_OK });\n debug.log(`[TimeToDisplay] ${spanToJSON(span).description} span updated with end timestamp.`);\n\n if (fullDisplayBeforeInitialDisplay.has(activeSpan)) {\n fullDisplayBeforeInitialDisplay.delete(activeSpan);\n debug.log(`[TimeToDisplay] Updating full display with initial display (${span.spanContext().spanId}) end.`);\n updateFullDisplaySpan(frameTimestampSeconds, span);\n }\n\n setSpanDurationAsMeasurementOnSpan('time_to_initial_display', span, activeSpan);\n}\n\nfunction updateFullDisplaySpan(frameTimestampSeconds: number, passedInitialDisplaySpan?: Span): void {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n debug.warn('[TimeToDisplay] No active span found to update ui.load.full_display in.');\n return;\n }\n\n const existingInitialDisplaySpan = passedInitialDisplaySpan\n || getSpanDescendants(activeSpan).find((span) => spanToJSON(span).op === 'ui.load.initial_display');\n const initialDisplayEndTimestamp = existingInitialDisplaySpan && spanToJSON(existingInitialDisplaySpan).timestamp;\n if (!initialDisplayEndTimestamp) {\n fullDisplayBeforeInitialDisplay.set(activeSpan, true);\n debug.warn(`[TimeToDisplay] Full display called before initial display for active span (${activeSpan.spanContext().spanId}).`);\n return;\n }\n\n const span = startTimeToFullDisplaySpan({\n isAutoInstrumented: true,\n });\n if (!span) {\n debug.warn('[TimeToDisplay] No TimeToFullDisplay span found or created, possibly performance is disabled.');\n return;\n }\n\n const spanJSON = spanToJSON(span);\n if (spanJSON.timestamp) {\n debug.warn(`[TimeToDisplay] ${spanJSON.description} (${spanJSON.span_id}) span already ended.`);\n return;\n }\n\n if (initialDisplayEndTimestamp > frameTimestampSeconds) {\n debug.warn('[TimeToDisplay] Using initial display end. Full display end frame timestamp is before initial display end.');\n span.end(initialDisplayEndTimestamp);\n } else {\n span.end(frameTimestampSeconds);\n }\n\n span.setStatus({ code: SPAN_STATUS_OK });\n debug.log(`[TimeToDisplay] ${spanJSON.description} (${spanJSON.span_id}) span updated with end timestamp.`);\n\n setSpanDurationAsMeasurement('time_to_full_display', span);\n}\n\n/**\n * Creates a new TimeToFullDisplay component which triggers the full display recording every time the component is focused.\n */\nexport function createTimeToFullDisplay({\n useFocusEffect,\n}: {\n /**\n * `@react-navigation/native` useFocusEffect hook.\n */\n useFocusEffect: (callback: () => void) => void\n}): React.ComponentType<TimeToDisplayProps> {\n return createTimeToDisplay({ useFocusEffect, Component: TimeToFullDisplay });\n}\n\n/**\n * Creates a new TimeToInitialDisplay component which triggers the initial display recording every time the component is focused.\n */\nexport function createTimeToInitialDisplay({\n useFocusEffect,\n}: {\n useFocusEffect: (callback: () => void) => void\n}): React.ComponentType<TimeToDisplayProps> {\n return createTimeToDisplay({ useFocusEffect, Component: TimeToInitialDisplay });\n}\n\nfunction createTimeToDisplay({\n useFocusEffect,\n Component,\n}: {\n /**\n * `@react-navigation/native` useFocusEffect hook.\n */\n useFocusEffect: (callback: () => void) => void;\n Component: typeof TimeToFullDisplay | typeof TimeToInitialDisplay;\n}): React.ComponentType<TimeToDisplayProps> {\n const TimeToDisplayWrapper = (props: TimeToDisplayProps): React.ReactElement => {\n const [focused, setFocused] = useState(false);\n\n useFocusEffect(() => {\n setFocused(true);\n return () => {\n setFocused(false);\n };\n });\n\n return <Component {...props} record={focused && props.record} />;\n };\n\n TimeToDisplayWrapper.displayName = 'TimeToDisplayWrapper';\n return TimeToDisplayWrapper;\n}\n"]}
|
package/dist/js/tracing/utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dropUndefinedKeys, getSpanDescendants,
|
|
1
|
+
import { debug, dropUndefinedKeys, getSpanDescendants, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT, SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, setMeasurement, spanToJSON, timestampInSeconds, uuid4, } from '@sentry/core';
|
|
2
2
|
import { RN_GLOBAL_OBJ } from '../utils/worldwide';
|
|
3
3
|
export const defaultTransactionSource = 'component';
|
|
4
4
|
export const customTransactionSource = 'custom';
|
|
@@ -71,7 +71,7 @@ export function getLatestChildSpanEndTimestamp(span) {
|
|
|
71
71
|
export function getBundleStartTimestampMs() {
|
|
72
72
|
const bundleStartTime = RN_GLOBAL_OBJ.__BUNDLE_START_TIME__;
|
|
73
73
|
if (!bundleStartTime) {
|
|
74
|
-
|
|
74
|
+
debug.warn('Missing the bundle start time on the global object.');
|
|
75
75
|
return undefined;
|
|
76
76
|
}
|
|
77
77
|
if (!RN_GLOBAL_OBJ.nativePerformanceNow) {
|