|
1 | 1 | --- |
2 | | -title: Scopes and Hubs |
| 2 | +title: Scopes |
3 | 3 | 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." |
4 | 4 | --- |
5 | 5 |
|
6 | 6 | When an event is captured and sent to Sentry, SDKs will merge that event data with extra |
7 | 7 | information from the current scope. SDKs will typically automatically manage the scopes |
8 | 8 | 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. |
10 | 10 |
|
11 | | -## What's a Scope, What's a Hub |
| 11 | +## What's a Scope? |
12 | 12 |
|
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 |
20 | 15 | [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. |
23 | 47 |
|
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: |
27 | 49 |
|
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 | +``` |
29 | 55 |
|
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> |
36 | 59 |
|
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 | +``` |
40 | 104 |
|
41 | 105 | ## Configuring the Scope |
42 | 106 |
|
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). |
44 | 108 |
|
45 | 109 | You'll first need to import the SDK, as usual: |
46 | 110 |
|
47 | 111 | <PlatformContent includePath="enriching-events/import" /> |
48 | 112 |
|
49 | 113 | You can, for instance, add custom tags or inform Sentry about the currently authenticated user. |
50 | 114 |
|
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 | +``` |
56 | 131 |
|
57 | 132 | 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/). |
59 | 134 |
|
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` |
67 | 136 |
|
68 | 137 | In the following example we use <PlatformIdentifier name="with-scope" /> to attach a `level` and a `tag` to only one specific error: |
69 | 138 |
|
70 | 139 | <PlatformContent includePath="enriching-events/scopes/with-scope" /> |
71 | 140 |
|
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 |
77 | 142 | more easily isolate pieces of context information to specific locations in your code or |
78 | 143 | even call <PlatformIdentifier name="clear" /> to briefly remove all context information. |
0 commit comments