Skip to content

Commit

Permalink
misc(expo-sample): Add expo-router auto instrumentation (#3688)
Browse files Browse the repository at this point in the history
* misc(sample): Move `Sentry.init` to the root `_layout`

* misc(sample): Do not execute Sentry in NodeJS during npx expo export command (#3689)

* feat(expo): Add getDefaultConfig option to getSentryExpoConfig (#3690)

* misc(sample): Do not execute Sentry in NodeJS during npx expo export command

* feat(expo): Add `getDefaultConfig` option to `getSentryExpoConfig`

* misc(sample): Enable expo-router auto instrumentation (#3692)

* misc(sample): Disable Expo Web static routes, export command hangs

* misc(sample): Enable expo-router auto instrumentation
  • Loading branch information
krystofwoldrich authored Mar 21, 2024
1 parent 93ab173 commit 1b30306
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 64 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- Add `getDefaultConfig` option to `getSentryExpoConfig` ([#3690](https://github.com/getsentry/sentry-react-native/pull/3690))

## 5.20.0

### Features
Expand Down
59 changes: 0 additions & 59 deletions samples/expo/app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,71 +3,12 @@ import Constants from 'expo-constants';
import * as Sentry from '@sentry/react-native';

import { Text, View } from '@/components/Themed';
import { SENTRY_INTERNAL_DSN } from '@/utils/dsn';
import { HttpClient } from '@sentry/integrations';
import { setScopeProperties } from '@/utils/setScopeProperties';
import { timestampInSeconds } from '@sentry/utils';
import React from 'react';

const isRunningInExpoGo = Constants.appOwnership === 'expo'

Sentry.init({
// Replace the example DSN below with your own DSN:
dsn: SENTRY_INTERNAL_DSN,
debug: true,
environment: 'dev',
beforeSend: (event: Sentry.Event) => {
console.log('Event beforeSend:', event.event_id);
return event;
},
beforeSendTransaction(event) {
console.log('Transaction beforeSend:', event.event_id);
return event;
},
// This will be called with a boolean `didCallNativeInit` when the native SDK has been contacted.
onReady: ({ didCallNativeInit }) => {
console.log('onReady called with didCallNativeInit:', didCallNativeInit);
},
integrations(integrations) {
integrations.push(
new HttpClient({
// These options are effective only in JS.
// This array can contain tuples of `[begin, end]` (both inclusive),
// Single status codes, or a combinations of both.
// default: [[500, 599]]
failedRequestStatusCodes: [[400, 599]],
// This array can contain Regexes or strings, or combinations of both.
// default: [/.*/]
failedRequestTargets: [/.*/],
}),
Sentry.metrics.metricsAggregatorIntegration(),
);
return integrations.filter(i => i.name !== 'Dedupe');
},
enableAutoSessionTracking: true,
// For testing, session close when 5 seconds (instead of the default 30) in the background.
sessionTrackingIntervalMillis: 5000,
// This will capture ALL TRACES and likely use up all your quota
enableTracing: true,
tracesSampleRate: 1.0,
tracePropagationTargets: ['localhost', /^\//, /^https:\/\//, /^http:\/\//],
attachStacktrace: true,
// Attach screenshots to events.
attachScreenshot: true,
// Attach view hierarchy to events.
attachViewHierarchy: true,
// Enables capture failed requests in JS and native.
enableCaptureFailedRequests: true,
// Sets the `release` and `dist` on Sentry events. Make sure this matches EXACTLY with the values on your sourcemaps
// otherwise they will not work.
// release: '[email protected]+1',
// dist: `1`,
_experiments: {
profilesSampleRate: 0,
},
enableSpotlight: true,
});

export default function TabOneScreen() {
const [componentMountStartTimestamp] = React.useState<number>(() => {
return timestampInSeconds();
Expand Down
83 changes: 81 additions & 2 deletions samples/expo/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import FontAwesome from '@expo/vector-icons/FontAwesome';
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native';
import { useFonts } from 'expo-font';
import { SplashScreen, Stack } from 'expo-router';
import { SplashScreen, Stack, useNavigationContainerRef } from 'expo-router';
import { useEffect } from 'react';

import { useColorScheme } from '@/components/useColorScheme';
import { HttpClient } from '@sentry/integrations';
import { SENTRY_INTERNAL_DSN } from '../utils/dsn';
import * as Sentry from '@sentry/react-native';
import { isExpoGo } from '../utils/isExpoGo';

export {
// Catch any errors thrown by the Layout component.
Expand All @@ -14,7 +18,80 @@ export {
// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();

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

process.env.EXPO_SKIP_DURING_EXPORT !== 'true' && Sentry.init({
// Replace the example DSN below with your own DSN:
dsn: SENTRY_INTERNAL_DSN,
debug: true,
environment: 'dev',
beforeSend: (event: Sentry.Event) => {
console.log('Event beforeSend:', event.event_id);
return event;
},
beforeSendTransaction(event) {
console.log('Transaction beforeSend:', event.event_id);
return event;
},
// This will be called with a boolean `didCallNativeInit` when the native SDK has been contacted.
onReady: ({ didCallNativeInit }) => {
console.log('onReady called with didCallNativeInit:', didCallNativeInit);
},
integrations(integrations) {
integrations.push(
new HttpClient({
// These options are effective only in JS.
// This array can contain tuples of `[begin, end]` (both inclusive),
// Single status codes, or a combinations of both.
// default: [[500, 599]]
failedRequestStatusCodes: [[400, 599]],
// This array can contain Regexes or strings, or combinations of both.
// default: [/.*/]
failedRequestTargets: [/.*/],
}),
Sentry.metrics.metricsAggregatorIntegration(),
new Sentry.ReactNativeTracing({
routingInstrumentation,
enableNativeFramesTracking: !isExpoGo(), // Only in native builds, not in Expo Go.
}),
);
return integrations.filter(i => i.name !== 'Dedupe');
},
enableAutoSessionTracking: true,
// For testing, session close when 5 seconds (instead of the default 30) in the background.
sessionTrackingIntervalMillis: 5000,
// This will capture ALL TRACES and likely use up all your quota
enableTracing: true,
tracesSampleRate: 1.0,
tracePropagationTargets: ['localhost', /^\//, /^https:\/\//, /^http:\/\//],
attachStacktrace: true,
// Attach screenshots to events.
attachScreenshot: true,
// Attach view hierarchy to events.
attachViewHierarchy: true,
// Enables capture failed requests in JS and native.
enableCaptureFailedRequests: true,
// Sets the `release` and `dist` on Sentry events. Make sure this matches EXACTLY with the values on your sourcemaps
// otherwise they will not work.
// release: '[email protected]+1',
// dist: `1`,
_experiments: {
profilesSampleRate: 0,
},
enableSpotlight: true,
});

function RootLayout() {
const ref = useNavigationContainerRef();

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

const [loaded, error] = useFonts({
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
...FontAwesome.font,
Expand Down Expand Up @@ -50,3 +127,5 @@ function RootLayoutNav() {
</ThemeProvider>
);
}

export default Sentry.wrap(RootLayout);
2 changes: 2 additions & 0 deletions samples/expo/metro.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require('@expo/metro-config');
const path = require('path');

const { getSentryExpoConfig } = require('../../metro');
Expand All @@ -7,6 +8,7 @@ const { getSentryExpoConfig } = require('../../metro');
const config = getSentryExpoConfig(__dirname, {
// [Web-only]: Enables CSS support in Metro.
isCSSEnabled: true,
getDefaultConfig,
});

config.watchFolders.push(path.resolve(__dirname, '../../node_modules/@sentry'));
Expand Down
3 changes: 2 additions & 1 deletion samples/expo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"ts:check": "tsc"
"ts:check": "tsc",
"export": "EXPO_SKIP_DURING_EXPORT='true' expo export --dump-sourcemap --clear"
},
"dependencies": {
"@types/react": "18.2.45",
Expand Down
5 changes: 5 additions & 0 deletions samples/expo/utils/isExpoGo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Constants, { AppOwnership } from 'expo-constants';

export function isExpoGo(): boolean {
return Constants.appOwnership === AppOwnership.Expo;
}
7 changes: 5 additions & 2 deletions src/js/tools/metroconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ export function withSentryConfig(config: MetroConfig): MetroConfig {
/**
* This function returns Default Expo configuration with Sentry plugins.
*/
export function getSentryExpoConfig(projectRoot: string, options: DefaultConfigOptions = {}): MetroConfig {
const { getDefaultConfig } = loadExpoMetroConfigModule();
export function getSentryExpoConfig(
projectRoot: string,
options: DefaultConfigOptions & { getDefaultConfig?: typeof getSentryExpoConfig } = {},
): MetroConfig {
const getDefaultConfig = options.getDefaultConfig || loadExpoMetroConfigModule().getDefaultConfig;
const config = getDefaultConfig(projectRoot, {
...options,
unstable_beforeAssetSerializationPlugins: [
Expand Down

0 comments on commit 1b30306

Please sign in to comment.