Skip to content

Commit 5873e41

Browse files
krystofwoldrichlizokmlucas-zimermanantonis
authored
Add React Native V6 Changes (#11320)
Co-authored-by: Liza Mock <[email protected]> Co-authored-by: LucasZF <[email protected]> Co-authored-by: Antonis Lilis <[email protected]>
1 parent 80c1987 commit 5873e41

File tree

31 files changed

+715
-710
lines changed

31 files changed

+715
-710
lines changed

docs/platforms/react-native/enriching-events/context/index.mdx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ Sentry.captureException(new Error("something went wrong"), () => scope);
8989

9090
Context is held in the current scope and thus is cleared when the scope is removed ("popped"). You can push and pop your own scopes to apply context data to a specific code block or function.
9191

92+
9293
Sentry supports two different ways for unsetting context:
9394

9495
1. Modifying, overwriting or clearing values on the current scope.
@@ -100,10 +101,10 @@ With the following snippet, the `user` context will be updated for all future ev
100101
Sentry.setUser(someUser);
101102
```
102103

103-
If you want to remove data from the current scope, you can call:
104+
If you want to remove all data from the current scope, you can call:
104105

105106
```javascript
106-
Sentry.configureScope((scope) => scope.clear());
107+
Sentry.getCurrentScope().clear();
107108
```
108109

109110
The following will only configure the `user` context for the error captured inside the `withScope` callback. The context will be automatically restored to the previous state afterwards:
Lines changed: 109 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,143 @@
11
---
2-
title: Scopes and Hubs
2+
title: Scopes
33
description: "SDKs will typically automatically manage the scopes for you in the framework integrations. Learn what a scope is and how you can use it to your advantage."
44
---
55

66
When an event is captured and sent to Sentry, SDKs will merge that event data with extra
77
information from the current scope. SDKs will typically automatically manage the scopes
88
for you in the framework integrations and you don't need to think about them. However,
9-
you should know what a scope is and how you can use it for your advantage.
9+
you should know what a scope is and how you can use it to your advantage.
1010

11-
## What's a Scope, What's a Hub
11+
## What's a Scope?
1212

13-
You can think of the hub as the central point that our SDKs use to route an
14-
event to Sentry. When you call `init()` a hub is created and a client and a
15-
blank scope are created on it. That hub is then associated with the current
16-
thread and will internally hold a stack of scopes.
17-
18-
The scope will hold useful information that should be sent along with the
19-
event. For instance [contexts](../context/) or
13+
Scopes hold useful information that gets sent along with the
14+
event. For instance, [contexts](../context/) and
2015
[breadcrumbs](../breadcrumbs/) are stored on
21-
the scope. When a scope is pushed, it inherits all data from the parent scope
22-
and when it pops all modifications are reverted.
16+
the scope. When a scope is forked, it inherits all data from its parent scope.
17+
18+
The default SDK integrations will fork scopes intelligently. For
19+
instance, web framework integrations will fork scopes around your
20+
routes or request handlers.
21+
22+
## How Scopes Work
23+
24+
Scopes are basically stacks of data that are attached to events. When an event is captured, the SDK will merge the data from the active scopes into the event. This allows you to attach data to events that is relevant to the context in which the event was captured.
25+
26+
A scope is generally valid inside of a callback or an execution context. This means that multiple parts of your application may have different scopes active at the same time. For instance, a web server might handle multiple requests at the same time, and each request may have different scope data to apply to its events.
27+
28+
## Different Kinds of Scopes
29+
30+
The Sentry SDK has three different kinds of scopes:
31+
32+
- [Global scope](#global-scope)
33+
- [Isolation scope](#isolation-scope)
34+
- [Current scope](#current-scope)
35+
36+
### Global Scope
37+
38+
The global scope is applied to _all_ events, no matter where they originate. You can use it to store data that should apply to all events, such as environmental information.
39+
40+
You can access the global scope via `Sentry.getGlobalScope()`.
41+
42+
Note, that the global scope can only be used to write data, not to capture events. Events can only be captured on the current scope (for example, `getCurrentScope().captureException()` and similar APIs).
43+
44+
### Isolation Scope
45+
46+
The isolation scope is used to isolate events from each other. For example, each request in a web server might get its own isolation scope, so that events from one request don't interfere with events from another. In most cases, you'll want to put data that should be applied to your events on the isolation scope. This is why all `Sentry.setXXX` methods, like `Sentry.setTag()` will write data onto the currently active isolation scope. A classic example of data that belongs on the isolation scope is user data, where each request may have a different user, so you'd want to make sure that the user is set on the isolation scope.
2347

24-
The default SDK integrations will push and pop scopes intelligently. For
25-
instance web framework integrations will create and destroy scopes around your
26-
routes or controllers.
48+
You can access the isolation scope via `Sentry.getIsolationScope()`, but usually you'll just use the `Sentry.setXXX` methods to set data on the currently active isolation scope:
2749

28-
## How the Scope and Hub Work
50+
```javascript
51+
Sentry.setTag("my-tag", "my value");
52+
// Is identical to:
53+
Sentry.getIsolationScope().setTag("my-tag", "my value");
54+
```
2955

30-
As you start using an SDK, a scope and hub are automatically created for you out
31-
of the box. It's unlikely that you'll interact with the hub directly unless you're
32-
writing an integration or you want to create or destroy scopes. Scopes, on the
33-
other hand are more user facing. You can call <PlatformIdentifier name="configure-scope" /> at any point in
34-
time to modify data stored on the scope. This is useful for doing things like
35-
[modifying the context](../context/).
56+
<PlatformCategorySection supported={["browser"]}>
57+
In the browser, the isolation scope is never forked because it's impossible to keep track of where an isolation scope would belong. This is why the isolation scope is effectively global in the browser.
58+
</PlatformCategorySection>
3659

37-
When you call a global function such as <PlatformIdentifier name="capture-event" /> internally Sentry
38-
discovers the current hub and asks it to capture an event. Internally the hub will
39-
then merge the event with the topmost scope's data.
60+
Note, that the isolation scope can only be used to write data, not to capture events. Events can only be captured on the current scope (for example, `getCurrentScope().captureException()` and similar APIs).
61+
62+
### Current Scope
63+
64+
Current scope is the local scope that's currently active. Unlike the rarely-forked isolation scope, the current scope may be forked more frequently and under the hood. It can be used to store data that should only be applied to specific events. In most cases, you shouldn't access this scope directly, but use `Sentry.withScope` to create a new scope that's only active for a specific part of your code:
65+
66+
```javascript
67+
Sentry.withScope((scope) => {
68+
// scope is the current scope inside of this callback!
69+
scope.setTag("my-tag", "my value");
70+
// this tag will only be applied to events captured inside of this callback
71+
// the following event will have the tag:
72+
Sentry.captureException(new Error("my error"));
73+
});
74+
// this event will not have the tag:
75+
Sentry.captureException(new Error("my other error"));
76+
```
77+
78+
You can access the current scope via `Sentry.getCurrentScope()`, but you should use `Sentry.withScope()` to interact with local scopes in most cases instead.
79+
80+
## How Scope Data is Applied to Events
81+
82+
Before an event (like an error or transaction) is sent to Sentry, the currently active scopes are applied to it.
83+
84+
The global scope is applied first, followed by the isolation scope, and finally the current scope. This means that any data set on the current scope will take precedence over data set on the isolation and global scopes:
85+
86+
```javascript
87+
Sentry.getGlobalScope().setExtras({
88+
shared: "global",
89+
global: "data",
90+
});
91+
Sentry.getIsolationScope().setExtras({
92+
shared: "isolation",
93+
isolation: "data",
94+
});
95+
Sentry.getCurrentScope().setExtras({
96+
shared: "current",
97+
current: "data",
98+
});
99+
100+
Sentry.captureException(new Error("my error"));
101+
// --> Will have the following extra:
102+
// { shared: 'current', global: 'data', isolation: 'data', current: 'data' }
103+
```
40104

41105
## Configuring the Scope
42106

43-
The most useful operation when working with scopes is the <PlatformIdentifier name="configure-scope" /> function. It can be used to reconfigure the current scope.
107+
There are two main ways to interact with the scope. You can access the current scope via `Sentry.getCurrentScope()` and use setters on the resulting scope, or you can use global methods like `Sentry.setTag()` directly, which will set on the respective scope under the hood (this will be the isolation scope).
44108

45109
You'll first need to import the SDK, as usual:
46110

47111
<PlatformContent includePath="enriching-events/import" />
48112

49113
You can, for instance, add custom tags or inform Sentry about the currently authenticated user.
50114

51-
<PlatformContent includePath="enriching-events/scopes/configure-scope" />
52-
53-
You can also apply this configuration when unsetting a user at logout:
54-
55-
<PlatformContent includePath="enriching-events/unset-user" />
115+
```javascript
116+
/// Usually, you don't want to write on the current scope, so use with care!
117+
const scope = Sentry.getCurrentScope();
118+
scope.setTag("my-tag", "my value");
119+
scope.setUser({
120+
id: 42,
121+
122+
});
123+
124+
// Or use the global methods (which will set data on the isolation scope):
125+
Sentry.setTag("my-tag", "my value");
126+
Sentry.setUser({
127+
id: 42,
128+
129+
});
130+
```
56131

57132
To learn what useful information can be associated with scopes see
58-
[the context documentation](../context/).
133+
[context](../context/), [tags](../tags), [users](../identify-user) and [breadcrumbs](../breadcrumbs/).
59134

60-
## Local Scopes
61-
62-
We also support pushing and configuring a scope within a single call. This is typically
63-
called <PlatformIdentifier name="with-scope" />, <PlatformIdentifier name="push-scope" /> or implemented as a function parameter on the capture methods, depending on the SDK. It's very helpful if
64-
you only want to send data for one specific event.
65-
66-
### Using <PlatformIdentifier name="with-scope" />
135+
## Using `withScope`
67136

68137
In the following example we use <PlatformIdentifier name="with-scope" /> to attach a `level` and a `tag` to only one specific error:
69138

70139
<PlatformContent includePath="enriching-events/scopes/with-scope" />
71140

72-
While this example looks similar to <PlatformIdentifier name="configure-scope" />, it is actually very different.
73-
Calls to <PlatformIdentifier name="configure-scope" /> change the current active scope; all successive calls to <PlatformIdentifier name="configure-scope" /> will maintain previously set changes unless they are explicitly unset.
74-
75-
On the other hand, <PlatformIdentifier name="with-scope" /> creates a clone of the current scope, and the changes
76-
made will stay isolated within the <PlatformIdentifier name="with-scope" /> callback function. This allows you to
141+
The scope inside the `withScope()` callback is only valid inside of the callback. Once the callback ends, the scope will be removed and will no longer apply. The inner scope is only applied to events that are captured inside of the callback. `withScope()` will clone (or fork) the current scope, so the current scope won't be modified. This allows you to
77142
more easily isolate pieces of context information to specific locations in your code or
78143
even call <PlatformIdentifier name="clear" /> to briefly remove all context information.

docs/platforms/react-native/enriching-events/transaction-name/index.mdx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@ A lot of our framework integrations already set a transaction name, though you c
2222

2323
You'll first need to import the SDK, as usual:
2424

25-
<PlatformContent includePath="enriching-events/import" />
25+
```javascript
26+
import * as Sentry from "@sentry/react-native";
27+
```
2628

2729
To override the name of the currently running transaction:
2830

29-
<PlatformContent includePath="enriching-events/set-transaction-name" />
31+
```javascript
32+
Sentry.getCurrentScope().setTransactionName("UserListView");
33+
```
3034

3135
Please refer to [the tracing documentation](../../tracing/) for how to start and stop transactions.

docs/platforms/react-native/index.mdx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Sentry captures data by using an SDK within your application's runtime. These ar
3838
To install, run `@sentry/wizard`:
3939

4040
```bash {tabTitle:npm}
41-
npx @sentry/wizard@latest -s -i reactNative
41+
npx @sentry/wizard@latest -i reactNative
4242
```
4343

4444
[Sentry Wizard](https://github.com/getsentry/sentry-wizard) will patch your project accordingly, though you can [set up manually](/platforms/react-native/manual-setup/manual-setup/) if you prefer. You only need to patch the project once. Then you can add the patched files to your version control system.
@@ -65,19 +65,17 @@ If you're using Expo, [read our docs](/platforms/react-native/manual-setup/expo/
6565
To capture all errors, initialize the Sentry React Native SDK as soon as possible.
6666

6767

68-
```javascript {filename:App.js} {"onboardingOptions": {"performance": "5-7", "profiling": "8-12"}}
68+
```javascript {filename:App.js} {"onboardingOptions": {"performance": "5-7", "profiling": "8-10"}}
6969
import * as Sentry from "@sentry/react-native";
7070

7171
Sentry.init({
7272
dsn: "___PUBLIC_DSN___",
7373
// Set tracesSampleRate to 1.0 to capture 100% of transactions for tracing.
7474
// We recommend adjusting this value in production.
7575
tracesSampleRate: 1.0,
76-
_experiments: {
77-
// profilesSampleRate is relative to tracesSampleRate.
78-
// Here, we'll capture profiles for 100% of transactions.
79-
profilesSampleRate: 1.0,
80-
},
76+
// profilesSampleRate is relative to tracesSampleRate.
77+
// Here, we'll capture profiles for 100% of transactions.
78+
profilesSampleRate: 1.0,
8179
});
8280
```
8381

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,115 @@
11
---
22
title: Custom Integrations
3+
sidebar_order: 200
34
description: "Learn how to enable a custom integration."
4-
sidebar_order: 3
55
---
66

7-
<Include name="platforms/configuration/integrations/custom.mdx" />
7+
In addition to the integrations that come with the SDK, you can also write custom integrations.
8+
9+
Custom integration must conform to the [Integration interface](https://github.com/getsentry/sentry-javascript/blob/master/packages/types/src/integration.ts).
10+
11+
A custom integration can be created and added to the SDK as follows:
12+
13+
```javascript
14+
function myAwesomeIntegration() {
15+
return {
16+
name: "MyAwesomeIntegration",
17+
setup(client) {
18+
// Do something when the SDK is initialized
19+
// The client that is being setup is passed to the hook
20+
},
21+
};
22+
}
23+
24+
Sentry.init({
25+
// ...
26+
integrations: [myAwesomeIntegration()],
27+
});
28+
```
29+
30+
All hooks on an integration are optional. The only required field is the `name`. You can use one or multiple of the following hooks in a custom integration:
31+
32+
### `setup`
33+
34+
The `setup` hook is called when the SDK is initialized. It receives the client instance as an argument.
35+
You should use this if you want to run some code upon initialization.
36+
37+
```javascript
38+
const integration = {
39+
name: "MyAwesomeIntegration",
40+
setup(client) {
41+
setupCustomSentryListener(client);
42+
},
43+
};
44+
```
45+
46+
### `processEvent`
47+
48+
This hook can be used to modify events before they're sent to Sentry. It receives the event as an argument and should return the modified event. The hook also receives a hint object that may hold additional event metadata, as well as the client that's sending the event. You can also return `null` to drop the event from being sent.
49+
50+
```javascript
51+
const integration = {
52+
name: "MyAwesomeIntegration",
53+
processEvent(event, hint, client) {
54+
event.extra = {
55+
...event.extra,
56+
myCustomTag: "value",
57+
};
58+
// Return the modified event,
59+
// or return `null` to drop the event
60+
return event;
61+
},
62+
};
63+
```
64+
65+
You can also return a promise that resolves with an event or `null`. However, this is not recommended and should be avoided wherever possible, because it can delay event sending.
66+
67+
### `preprocessEvent`
68+
69+
This hook is similar to `processEvent`, but it's called before the event is passed to any other `processEvent` hook. It can be used in places where the order of processing is important.
70+
71+
You can use `processEvent` for most cases, but only when you need to ensure that your hook is called before any other `processEvent` hook use `preprocessEvent`.
72+
73+
Similar to `processEvent`, this hook receives the event, hint, and client as arguments. However, this hook won't allow the return of a modified event or `null` to drop the event. You can only mutate the passed in event in this hook:
74+
75+
```javascript
76+
const integration = {
77+
name: "MyAwesomeIntegration",
78+
preprocessEvent(event, hint, client) {
79+
event.extra = {
80+
...event.extra,
81+
myCustomTag: "value",
82+
};
83+
// Nothing to return, just mutate the event
84+
},
85+
};
86+
```
87+
88+
### `setupOnce`
89+
90+
This hook is similar to `setup`, but it's only run once, even if the SDK is re-initialized. It won't receive any arguments. We recommend that you use `setup` instead. The only reason to use `setupOnce` is when you may be calling `Sentry.init()` multiple times and you want to ensure a certain piece of code is only run once.
91+
92+
```javascript
93+
const integration = {
94+
name: "MyAwesomeIntegration",
95+
setupOnce() {
96+
wrapLibrary();
97+
},
98+
};
99+
```
100+
101+
### `afterAllSetup`
102+
103+
While we recommend that you use the `setup` hook in most cases, `afterAllSetup` can be used to make sure that all other integrations have been run. This hook receives the `client` that is being set up as the first argument and is triggered after `setupOnce()` and `setup()` have been called for all integrations.
104+
105+
106+
```javascript
107+
const integration = {
108+
name: "MyAwesomeIntegration",
109+
afterAllSetup(client) {
110+
// We can be sure that all other integrations
111+
// have run their `setup` and `setupOnce` hooks now
112+
startSomeThing(client);
113+
},
114+
};
115+
```

0 commit comments

Comments
 (0)