Skip to content

Commit

Permalink
ref: Navigation Integrations with new function style (#4003)
Browse files Browse the repository at this point in the history
  • Loading branch information
krystofwoldrich committed Aug 14, 2024
1 parent eeb83da commit 643c544
Show file tree
Hide file tree
Showing 25 changed files with 681 additions and 873 deletions.
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,44 @@
});
```

- New React Navigation Integration interface ([#4003](https://github.com/getsentry/sentry-react-native/pull/4003))

```js
import Sentry from '@sentry/react-native';
import { NavigationContainer } from '@react-navigation/native';
const reactNavigationIntegration = Sentry.reactNavigationIntegration();
Sentry.init({
tracesSampleRate: 1.0,
integrations: [reactNavigationIntegration],
});
function RootComponent() {
const navigation = React.useRef(null);
return <NavigationContainer ref={navigation}
onReady={() => {
reactNavigationIntegration.registerNavigationContainer(navigation);
}}>
</NavigationContainer>;
}
```

- New React Native Navigation Integration interface ([#4003](https://github.com/getsentry/sentry-react-native/pull/4003))

```js
import Sentry from '@sentry/react-native';
import { Navigation } from 'react-native-navigation';
Sentry.init({
tracesSampleRate: 1.0,
integrations: [
Sentry.reactNativeNavigationIntegration({ navigation: Navigation })
],
});
```

### Features

- `TimeToInitialDisplay` and `TimeToFullDisplay` start the time to display spans on mount ([#4020](https://github.com/getsentry/sentry-react-native/pull/4020))
Expand Down
9 changes: 4 additions & 5 deletions samples/expo/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ LogBox.ignoreAllLogs();
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();

const routingInstrumentation = new Sentry.ReactNavigationInstrumentation({
const navigationIntegration = Sentry.reactNavigationIntegration({
enableTimeToInitialDisplay: !isExpoGo(), // This is not supported in Expo Go.
});

Expand Down Expand Up @@ -54,9 +54,8 @@ process.env.EXPO_SKIP_DURING_EXPORT !== 'true' && Sentry.init({
// default: [/.*/]
failedRequestTargets: [/.*/],
}),
Sentry.reactNativeTracingIntegration({
routingInstrumentation,
}),
navigationIntegration,
Sentry.reactNativeTracingIntegration(),
);
return integrations.filter(i => i.name !== 'Dedupe');
},
Expand Down Expand Up @@ -91,7 +90,7 @@ function RootLayout() {

useEffect(() => {
if (ref) {
routingInstrumentation.registerNavigationContainer(ref);
navigationIntegration.registerNavigationContainer(ref);
}
}, [ref]);

Expand Down
15 changes: 7 additions & 8 deletions samples/react-native/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ LogBox.ignoreAllLogs();

const isMobileOs = Platform.OS === 'android' || Platform.OS === 'ios';

const reactNavigationInstrumentation =
new Sentry.ReactNavigationInstrumentation({
routeChangeTimeoutMs: 500, // How long it will wait for the route change to complete. Default is 1000ms
enableTimeToInitialDisplay: isMobileOs,
});
const reactNavigationIntegration = Sentry.reactNavigationIntegration({
routeChangeTimeoutMs: 500, // How long it will wait for the route change to complete. Default is 1000ms
enableTimeToInitialDisplay: isMobileOs,
ignoreEmptyBackNavigationTransactions: true,
});

Sentry.init({
// Replace the example DSN below with your own DSN:
Expand All @@ -66,11 +66,10 @@ Sentry.init({
},
integrations(integrations) {
integrations.push(
reactNavigationIntegration,
Sentry.reactNativeTracingIntegration({
// The time to wait in ms until the transaction will be finished, For testing, default is 1000 ms
idleTimeoutMs: 5_000,
routingInstrumentation: reactNavigationInstrumentation,
ignoreEmptyBackNavigationTransactions: true,
}),
Sentry.httpClientIntegration({
// These options are effective only in JS.
Expand Down Expand Up @@ -183,7 +182,7 @@ function BottomTabs() {
<NavigationContainer
ref={navigation}
onReady={() => {
reactNavigationInstrumentation.registerNavigationContainer(navigation);
reactNavigationIntegration.registerNavigationContainer(navigation);
}}>
<Tab.Navigator
screenOptions={{
Expand Down
14 changes: 0 additions & 14 deletions src/js/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ import type {
import { dateTimestampInSeconds, logger, SentryError } from '@sentry/utils';
import { Alert } from 'react-native';

import { createIntegration } from './integrations/factory';
import { defaultSdkInfo } from './integrations/sdkinfo';
import type { ReactNativeClientOptions } from './options';
import type { mobileReplayIntegration } from './replay/mobilereplay';
import { MOBILE_REPLAY_INTEGRATION_NAME } from './replay/mobilereplay';
import { getReactNativeTracingIntegration } from './tracing/reactnativetracing';
import { createUserFeedbackEnvelope, items } from './utils/envelope';
import { ignoreRequireCycleLogs } from './utils/ignorerequirecyclelogs';
import { mergeOutcomes } from './utils/outcome';
Expand Down Expand Up @@ -136,18 +134,6 @@ export class ReactNativeClient extends BaseClient<ReactNativeClientOptions> {
this._initNativeSdk();
}

/**
* @inheritdoc
*/
protected _setupIntegrations(): void {
super._setupIntegrations();
const tracing = getReactNativeTracingIntegration(this);
const routingName = tracing?.options?.routingInstrumentation?.name;
if (routingName) {
this.addIntegration(createIntegration(routingName));
}
}

/**
* Starts native client with dsn and options
*/
Expand Down
11 changes: 7 additions & 4 deletions src/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,18 @@ export { TouchEventBoundary, withTouchEventBoundary } from './touchevents';

export {
reactNativeTracingIntegration,
ReactNavigationV5Instrumentation,
ReactNavigationInstrumentation,
ReactNativeNavigationInstrumentation,
RoutingInstrumentation,
getCurrentReactNativeTracingIntegration,
getReactNativeTracingIntegration,
reactNavigationIntegration,
reactNativeNavigationIntegration,
sentryTraceGesture,
TimeToInitialDisplay,
TimeToFullDisplay,
startTimeToInitialDisplaySpan,
startTimeToFullDisplaySpan,
startIdleNavigationSpan,
startIdleSpan,
getDefaultIdleNavigationSpanOptions,
} from './tracing';

export type { TimeToDisplayProps } from './tracing';
13 changes: 5 additions & 8 deletions src/js/tracing/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
export {
reactNativeTracingIntegration,
INTEGRATION_NAME as REACT_NATIVE_TRACING_INTEGRATION_NAME,
getCurrentReactNativeTracingIntegration,
getReactNativeTracingIntegration,
} from './reactnativetracing';
export type { ReactNativeTracingIntegration } from './reactnativetracing';

export type { RoutingInstrumentationInstance } from './routingInstrumentation';
export { RoutingInstrumentation } from './routingInstrumentation';
export { reactNavigationIntegration } from './reactnavigation';
export { reactNativeNavigationIntegration } from './reactnativenavigation';

export {
ReactNavigationInstrumentation,
// eslint-disable-next-line deprecation/deprecation
ReactNavigationV5Instrumentation,
} from './reactnavigation';
export { ReactNativeNavigationInstrumentation } from './reactnativenavigation';
export { startIdleNavigationSpan, startIdleSpan, getDefaultIdleNavigationSpanOptions } from './span';

export type { ReactNavigationCurrentRoute, ReactNavigationRoute } from './types';

Expand Down
11 changes: 3 additions & 8 deletions src/js/tracing/integrations/appStart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {
APP_START_WARM as APP_START_WARM_OP,
UI_LOAD as UI_LOAD_OP,
} from '../ops';
import { getReactNativeTracingIntegration } from '../reactnativetracing';
import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '../semanticAttributes';
import { createChildSpanJSON, createSpanJSON, getBundleStartTimestampMs } from '../utils';

Expand Down Expand Up @@ -97,7 +96,7 @@ export function _clearRootComponentCreationTimestampMs(): void {
* Adds AppStart spans from the native layer to the transaction event.
*/
export const appStartIntegration = ({
standalone: standaloneUserOption,
standalone = false,
}: {
/**
* Should the integration send App Start as a standalone root span (transaction)?
Expand All @@ -108,7 +107,6 @@ export const appStartIntegration = ({
standalone?: boolean;
} = {}): AppStartIntegration => {
let _client: Client | undefined = undefined;
let standalone = standaloneUserOption;
let isEnabled = true;
let appStartDataFlushed = false;

Expand All @@ -123,11 +121,8 @@ export const appStartIntegration = ({
}
};

const afterAllSetup = (client: Client): void => {
if (standaloneUserOption === undefined) {
// If not user defined, set based on the routing instrumentation presence
standalone = !getReactNativeTracingIntegration(client)?.options.routingInstrumentation;
}
const afterAllSetup = (_client: Client): void => {
// TODO: automatically set standalone based on the presence of the native layer navigation integration
};

const processEvent = async (event: Event): Promise<Event> => {
Expand Down
17 changes: 14 additions & 3 deletions src/js/tracing/onSpanEndUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { AppState } from 'react-native';
import { isRootSpan, isSentrySpan } from '../utils/span';

/**
*
* Hooks on span end event to execute a callback when the span ends.
*/
export function onThisSpanEnd(client: Client, span: Span, callback: (span: Span) => void): void {
client.on('spanEnd', (endedSpan: Span) => {
Expand Down Expand Up @@ -44,7 +44,18 @@ export const adjustTransactionDuration = (client: Client, span: Span, maxDuratio
}
});
};
export const ignoreEmptyBackNavigation = (client: Client, span: Span): void => {

export const ignoreEmptyBackNavigation = (client: Client | undefined, span: Span): void => {
if (!client) {
logger.warn('Could not hook on spanEnd event because client is not defined.');
return;
}

if (!span) {
logger.warn('Could not hook on spanEnd event because span is not defined.');
return;
}

if (!isRootSpan(span) || !isSentrySpan(span)) {
logger.warn('Not sampling empty back spans only works for Sentry Transactions (Root Spans).');
return;
Expand All @@ -70,7 +81,7 @@ export const ignoreEmptyBackNavigation = (client: Client, span: Span): void => {
if (filtered.length <= 0) {
// filter children must include at least one span not created by the navigation automatic instrumentation
logger.log(
'[ReactNativeTracing] Not sampling transaction as route has been seen before. Pass ignoreEmptyBackNavigationTransactions = false to disable this feature.',
'Not sampling transaction as route has been seen before. Pass ignoreEmptyBackNavigationTransactions = false to disable this feature.',
);
// Route has been seen before and has no child spans.
span['_sampled'] = false;
Expand Down
Loading

0 comments on commit 643c544

Please sign in to comment.