Skip to content

Commit c7a4107

Browse files
feat(react-native): React Native auto performance docs (#2908)
* wip: Just write out what needs to be mentioned for RN auto perf * ref: Update tracing import * feat: Split up JS and RN auto instrumentation page, and write up. * ref: Code review suggestions Co-authored-by: Fiona <[email protected]> Co-authored-by: Fiona <[email protected]>
1 parent 2ca5f9d commit c7a4107

File tree

1 file changed

+220
-0
lines changed

1 file changed

+220
-0
lines changed

src/platforms/common/performance/capturing/automatic.mdx

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ title: Automatic Instrumentation
33
sidebar_order: 10
44
supported:
55
- javascript
6+
- react-native
67
description: "Learn how to add automatic instrumentation to captured transactions."
78
---
89

10+
<PlatformSection supported={["javascript"]} notSupported={["react-native"]}>
11+
912
<Note>
1013

1114
To _automatically_ capture transactions, you must first <PlatformLink to="/performance/">enable tracing in your app.</PlatformLink>
@@ -47,3 +50,220 @@ For `pageload` and `navigation` transactions, the `BrowserTracing` integration u
4750
This function can be used to filter out unwanted spans such as XHR's running health checks or something similar. By default `shouldCreateSpanForRequest` already filters out everything but what was defined in `tracingOrigins`.
4851

4952
<PlatformContent includePath="performance/filter-span-example" />
53+
54+
</PlatformSection>
55+
56+
<PlatformSection supported={["react-native"]} notSupported={["javascript"]}>
57+
58+
<Alert level="warning" title="Note">
59+
Automatic instrumentation is currently in beta, available on the Sentry React Native SDK version ≥ 2.2.0-beta.0. As a result, the API may change without warning.
60+
</Alert>
61+
62+
`@sentry/react-native` provides a `ReactNativeTracing` integration to add _automatic_ instrumentation for monitoring the performance of React Native applications.
63+
64+
## What Automatic Instrumentation Provides
65+
66+
The `ReactNativeTracing` integration creates a child span for every `XMLHttpRequest` or `fetch` request on the Javascript layer that occurs while those transactions are open. Learn more about [traces, transactions, and spans](/product/performance/distributed-tracing/).
67+
68+
## Enable Automatic Instrumentation
69+
70+
To enable automatic tracing, include the `ReactNativeTracing` integration in your SDK configuration options.
71+
72+
```javascript
73+
import * as Sentry from "@sentry/react-native";
74+
75+
Sentry.init({
76+
dsn: "___PUBLIC_DSN___",
77+
78+
integrations: [
79+
new Sentry.ReactNativeTracing({
80+
tracingOrigins: ["localhost", "my-site-url.com", /^\//],
81+
// ... other options
82+
}),
83+
],
84+
85+
// We recommend adjusting this value in production, or using tracesSampler
86+
// for finer control
87+
tracesSampleRate: 1.0,
88+
});
89+
```
90+
91+
Next, instrument your app with [routing instrumentation](#enable-routing-instrumentation).
92+
93+
## Configuration Options
94+
95+
You can pass many different options to the `ReactNativeTracing` integration (as an object of the form `{optionName: value}`), but it comes with reasonable defaults out of the box. For all possible options, see [TypeDocs](https://getsentry.github.io/sentry-javascript/interfaces/tracing.browsertracingoptions.html).
96+
97+
### tracingOrigins
98+
99+
The default value of `tracingOrigins` is `['localhost', /^\//]`. The React Native SDK will attach the `sentry-trace` header to all outgoing XHR/fetch requests whose destination contains a string in the list or matches a regex in the list. If your frontend is making requests to a different domain, you will need to add the domain there to propagate the `sentry-trace` header to the backend services, which is required to link transactions together as part of a single trace. **The `tracingOrigins` option matches against the entire request URL, not just the domain. Using stricter regex to match certain parts of the URL ensures that requests do not unnecessarily have the `sentry-trace` header attached.**
100+
101+
<PlatformContent includePath="performance/tracingOrigins-example" />
102+
103+
You will need to configure your web server CORS to allow the `sentry-trace` header. The configuration might look like `"Access-Control-Allow-Headers: sentry-trace"`, but the configuration depends on your setup. If you do not allow the `sentry-trace` header, the request might be blocked.
104+
105+
### shouldCreateSpanForRequest
106+
107+
This function can be used to filter out unwanted spans, such as XHR's running health checks or something similar. By default `shouldCreateSpanForRequest` already filters out everything except what was defined in `tracingOrigins`.
108+
109+
<PlatformContent includePath="performance/filter-span-example" />
110+
111+
## Enable Routing Instrumentation
112+
113+
We currently provide two routing instrumentations out of the box to instrument route changes for React Navigation V5 and V4. In the future, we will add support for other libraries such as [react-native-navigation](https://github.com/wix/react-native-navigation). Otherwise, if you have a custom routing instrumentation, or use a routing library we don't yet support, you can use the bare bones routing instrumentation or create your own by extending it.
114+
115+
### React Navigation V5
116+
117+
Note that this routing instrumentation will create a transaction on every route change including `goBack` navigations.
118+
119+
```js
120+
import * as Sentry from "@sentry/react-native";
121+
122+
// Construct a new instrumentation instance. This is needed to communicate between the integration and React
123+
const routingInstrumentation = new Sentry.ReactNavigationV5Instrumentation();
124+
125+
Sentry.init({
126+
...
127+
integrations: [
128+
new Sentry.ReactNativeTracing({
129+
// Pass instrumentation to be used as `routingInstrumentation`
130+
routingInstrumentation,
131+
// ...
132+
}),
133+
],
134+
})
135+
136+
const App = () => {
137+
// Create a ref for the navigation container
138+
const navigation = React.createRef<NavigationContainerRef>();
139+
140+
// Register the navigation container with the instrumentation
141+
React.useEffect(() => {
142+
routingInstrumentation.registerNavigationContainer(navigation);
143+
}, []);
144+
145+
return (
146+
// Connect the ref to the navigation container
147+
<NavigationContainer ref={navigation}>
148+
...
149+
</NavigationContainer>
150+
);
151+
};
152+
```
153+
154+
### React Navigation V4
155+
156+
Note that this routing instrumentation will create a transaction on every route change including `goBack` navigations.
157+
158+
```js
159+
// Construct a new instrumentation instance. This is needed to communicate between the integration and React
160+
const routingInstrumentation = new Sentry.ReactNavigationV4Instrumentation();
161+
162+
Sentry.init({
163+
...
164+
integrations: [
165+
new Sentry.ReactNativeTracing({
166+
// Pass instrumentation to be used as `routingInstrumentation`
167+
routingInstrumentation,
168+
...
169+
}),
170+
],
171+
})
172+
173+
const App = () => {
174+
// Create a ref for the navigation container
175+
const appContainer = React.createRef();
176+
177+
// Register the navigation container with the instrumentation
178+
React.useEffect(() => {
179+
routingInstrumentation.registerAppContainer(appContainer);
180+
}, []);
181+
182+
return (
183+
// Connect the ref to the navigation container
184+
<AppContainer ref={appContainer} />
185+
);
186+
};
187+
```
188+
189+
### Other Routing Libraries or Custom Routing Implementations
190+
191+
If you use another routing library that we don't yet support, or have a custom routing solution, you can use the basic `RoutingInstrumentation` we provide, or extend it to create your own instrumentation.
192+
193+
Every routing instrumentation revoles around one method:
194+
195+
`onRouteWillChange` (context: TransactionContext): Transaction | undefined
196+
197+
You need to ensure that this method is called **before** the route change occurs, and an `IdleTransaction` is created and set on the scope.
198+
199+
#### Bare Bones
200+
201+
```js
202+
// Construct a new instrumentation instance. This is needed to communicate between the integration and React
203+
const routingInstrumentation = new Sentry.RoutingInstrumentation();
204+
205+
Sentry.init({
206+
...
207+
integrations: [
208+
new Sentry.ReactNativeTracing({
209+
// Pass instrumentation to be used as `routingInstrumentation`
210+
routingInstrumentation,
211+
...
212+
}),
213+
],
214+
})
215+
216+
const App = () => {
217+
<SomeNavigationLibrary
218+
onRouteWillChange={(newRoute) => {
219+
// Call this before the route changes
220+
routingInstrumentation.onRouteWillChange({
221+
name: newRoute.name,
222+
op: 'navigation'
223+
})
224+
}}
225+
/>
226+
};
227+
```
228+
229+
#### Custom Instrumentation
230+
231+
```js
232+
class CustomInstrumentation extends RoutingInstrumentation {
233+
constructor(navigator) {
234+
super();
235+
236+
this.navigator.registerRouteChangeListener(this.routeListener.bind(this));
237+
}
238+
239+
routeListener(newRoute) {
240+
// Again, ensure this is called BEFORE the route changes and BEFORE the route is mounted.
241+
this.onRouteWillChange({
242+
name: newRoute.name,
243+
op: "navigation",
244+
});
245+
}
246+
}
247+
```
248+
249+
## Recipes
250+
251+
Currently, by default, the React Native SDK will only create child spans for fetch/XHR transactions out of the box. This means once you are done setting up your routing instrumentation, you will either see just a few fetch/XHR child spans or no children at all. To find out how to manually instrument your app, review our <PlatformLink to="/performance/capturing/manual/">Manual Instrumentation</PlatformLink>.
252+
253+
### React Profiler
254+
255+
We export the React Profiler from our React Native SDK as well, you can read more at [React Profiler](/platforms/javascript/guides/react/components/profiler/).
256+
257+
After you instrument your app's routing, if you wrap a component that renders on one of the routes with `withProfiler`, you will be able to track the component's lifecycle as a child span of the route transaction.
258+
259+
```js
260+
import * as Sentry from "@sentry/react-native";
261+
262+
const SomeComponent = () => {
263+
// ...
264+
};
265+
266+
export default Sentry.withProfiler(SomeComponent);
267+
```
268+
269+
</PlatformSection>

0 commit comments

Comments
 (0)