|
| 1 | +--- |
| 2 | +alwaysApply: false |
| 3 | +description: Java SDK Hubs and Scopes |
| 4 | +--- |
| 5 | +# Java SDK Hubs and Scopes |
| 6 | + |
| 7 | +## `Scopes` |
| 8 | + |
| 9 | +`Scopes` implements `IScopes` and manages three `Scope` instances, `global`, `isolation` and `current` scope. |
| 10 | +For some data, all three `Scope` instances are combined, for others, a certain one is used exclusively and for some we look at each scope in a certain order and use the data of the first scope that has the data set. This logic is contained in `CombinedScopeView`. |
| 11 | +Data itself is stored on `Scope` instances. |
| 12 | +`Scopes` also has a `parent` field, linking the `Scopes` it was forked off of and a `creator` String, explaining why it was forked. |
| 13 | + |
| 14 | +## `Hub` |
| 15 | + |
| 16 | +Up until major version 7 of the Java SDK the `IHub` interface was a central part of the SDK. |
| 17 | +In major version 8 we replaced the `IHub` interface with `IScopes`. `IHub` has been deprecated. |
| 18 | +While there is some bridging code in place to allow for easier migration, we are planning to remove it in an upcoming major. |
| 19 | + |
| 20 | +## Scope Types |
| 21 | + |
| 22 | +We have introduced some new Scope types in the SDK, allowing for better control over what data is attached where. |
| 23 | +Previously there was a stack of scopes that was pushed and popped. |
| 24 | +Instead we now fork scopes for a given lifecycle and then restore the previous scopes. |
| 25 | +Since Hub is gone, it is also never cloned anymore. |
| 26 | +Separation of data now happens through the different scope types while making it easier to manipulate exactly what you need without having to attach data at the right time to have it apply where wanted. |
| 27 | + |
| 28 | +### Global Scope |
| 29 | + |
| 30 | +Global scope is attached to all events created by the SDK. |
| 31 | +It can also be modified before Sentry.init has been called. |
| 32 | +It can be manipulated using `Sentry.configureScope(ScopeType.GLOBAL, (scope) -> { ... })`. |
| 33 | + |
| 34 | +Global scope can be retrieved from `Scopes` via `getGlobalScope`. It can also be retrieved directly via `Sentry.getGlobalScope`. |
| 35 | + |
| 36 | +### Isolation Scope |
| 37 | + |
| 38 | +Isolation scope can be used e.g. to attach data to all events that come up while handling an incoming request. |
| 39 | +It can also be used for other isolation purposes. |
| 40 | +It can be manipulated using `Sentry.configureScope(ScopeType.ISOLATION, (scope) -> { ... })`. |
| 41 | +The SDK automatically forks isolation scope in certain cases like incoming requests, CRON jobs, Spring `@Async` and more. |
| 42 | + |
| 43 | +Isolation scope can be retrieved from `Scopes` via `getIsolationScope`. |
| 44 | + |
| 45 | +### Current scope |
| 46 | + |
| 47 | +Current scope is forked often and data added to it is only added to events that are created while this scope is active. |
| 48 | +Data is also passed on to newly forked child scopes but not to parents. |
| 49 | + |
| 50 | +Current scope can be retrieved from `Scopes` via `getScope`. |
| 51 | + |
| 52 | +## Storage of `Scopes` |
| 53 | + |
| 54 | +`Scopes` are stored in a `ThreadLocal` by default (NOTE: this is different for OpenTelemetry, see opentelemetry.mdc). |
| 55 | +This happens through `Sentry.scopesStorage` and `DefaultScopesStorage`. |
| 56 | + |
| 57 | +The lifetime of `Scopes` in the thread local is managed by `ISentryLifecycleToken`. |
| 58 | +When the scopes are forked, they are stored into the `ThreadLocal` and a `ISentryLifecycleToken` is returned. |
| 59 | +When the `Scopes` are no longer needed, e.g. because a request is finished, `ISentryLifecycleToken.close` can be called to restore the previous state of the `ThreadLocal`. |
| 60 | + |
| 61 | +## Old versions of the Java SDK |
| 62 | + |
| 63 | +There were several implementations of the `IHub` interface: |
| 64 | +- `Hub` managed a stack of `Scope` instances, which were pushed and popped. |
| 65 | +- A `Hub` could be cloned, meaning there could be multiple stacks of scopes active, e.g. for two separate requests being handled in a server application. |
| 66 | + |
| 67 | +### Migrating to major version 8 of the SDK |
| 68 | + |
| 69 | +`IHub` has been replaced by `IScopes` |
| 70 | +`HubAdapter` has been replaced by `ScopesAdapter` |
| 71 | +`Hub.clone` should be replaced by using `pushScope` or `pushIsolationScope` |
| 72 | +`Sentry.getCurrentHub` has been replaced by `Sentry.getCurrentScopes` |
| 73 | +`Sentry.popScope` has been deprecated. Instead `close` should be called on the `ISentryLifecycleToken` returned e.g. by `pushScope`. This can also be done in a `try-with-resource` block. |
| 74 | + |
| 75 | +## `globalHubMode` |
| 76 | +The SDK has a `globalHubMode` option which affects forking behaviour of the SDK. |
| 77 | + |
| 78 | +Android has `globalHubMode` enabled by default. |
| 79 | +For JVM Desktop applications, `globalHubMode` can be used. |
| 80 | +For JVM Backend applications (servers) we discourage enabling `globalHubMode` since it will cause scopes to bleed into each other. This can e.g. mean that state from request A leaks into request B and events sent to Sentry contain a mix of both request A and B potentially rendering the data useless. |
| 81 | + |
| 82 | +### Enabled |
| 83 | + |
| 84 | +If `globalHubMode` is enabled, the SDK avoids forking scopes. |
| 85 | + |
| 86 | +This means, retrieving current scopes on a thread where specific scopes do not exist yet for the thread, the root scopes are not forked but returned directly. |
| 87 | +The SDK also doesn't fork scopes when `Sentry.pushScope`, `Sentry.pushIsolation`, `Sentry.withScope` or `Sentry.withIsolationScope` are executed. |
| 88 | + |
| 89 | +The suppression of forking via `globalHubMode` only applies when using `Sentry` static API or `ScopesAdapter`. |
| 90 | +In case the `Scopes` instance is accessed directly, forking will happen as if `globalHubMode` is disabled. |
| 91 | +However, while it's possible to use `Sentry.setCurrentScopes` it does not have any effect due to `Sentry.getCurrentScopes` directly returning `rootScopes` if `globalHubMode` is enabled. |
| 92 | +This means the forked scopes have to be managed manually, e.g. by keeping a reference and accessing Sentry API via the reference instead of using static API. |
| 93 | + |
| 94 | +`ScopesAdapter` makes use of the static `Sentry` API internally. It allows us to access the correct scopes for the current context without passing it along explicitly. It also makes testing easier. |
| 95 | + |
| 96 | +### Disabled |
| 97 | + |
| 98 | +If `globalHubMode` is disabled, the SDK forks scopes freely, e.g. when: |
| 99 | +- `Sentry.getCurrentScopes()` is executed on a Thread where no specific scopes for that thread have been stored yet. In this case the SDK will fork `rootScopes` (stored in a `Sentry` static property). |
| 100 | +- `withScope` or `withIsolationScope` are executed |
| 101 | +- `pushScope` or `pushIsolationScope` are executed |
| 102 | + |
| 103 | +## `defaultScopeType` |
| 104 | + |
| 105 | +The `defaultScopeType` controls which `Scope` instance is being used for writing to and reading from as a default value. |
| 106 | +When using API like `Sentry.setTag` the SDK adds that tag to the default `Scope`. |
| 107 | + |
| 108 | +This also ensures, customers who migrate to the latest SDK version and already have `Sentry.configureScope` invocations in place, will now write to the default `Scope` instance that was chosen. |
| 109 | + |
| 110 | +The default value for `defaultScopeType` is `ISOLATION` scope for JVM and `CURRENT` scope for Android. |
| 111 | + |
| 112 | +Which fields are written/read from/to `defaultScopeType` is controlled in `CombinedScopeView`. |
0 commit comments