From 3e48e746e69489336d265938b333eb986a832447 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Mon, 17 Jun 2024 14:01:35 +0200 Subject: [PATCH 1/2] feat: Update unified API page --- src/components/sidebar.tsx | 4 +- src/docs/sdk/hub-based-api/index.mdx | 274 ++++++ .../sdk/hub-based-api/unified-api.excalidraw | 796 ++++++++++++++++++ src/docs/sdk/hub-based-api/unified-api.png | Bin 0 -> 101906 bytes src/docs/sdk/unified-api/index.mdx | 265 ++++-- 5 files changed, 1254 insertions(+), 85 deletions(-) create mode 100644 src/docs/sdk/hub-based-api/index.mdx create mode 100644 src/docs/sdk/hub-based-api/unified-api.excalidraw create mode 100644 src/docs/sdk/hub-based-api/unified-api.png diff --git a/src/components/sidebar.tsx b/src/components/sidebar.tsx index 55a14e255d..8470746a7a 100644 --- a/src/components/sidebar.tsx +++ b/src/components/sidebar.tsx @@ -195,8 +195,9 @@ export default () => { Philosophy Basics Overview - Craft Quick Start + + Hub & Scope Refactoring Expected Features Data Handling @@ -278,6 +279,7 @@ export default () => { AWS Lambda Store Endpoint + Craft Quick Start
  • diff --git a/src/docs/sdk/hub-based-api/index.mdx b/src/docs/sdk/hub-based-api/index.mdx new file mode 100644 index 0000000000..a539592827 --- /dev/null +++ b/src/docs/sdk/hub-based-api/index.mdx @@ -0,0 +1,274 @@ +--- +title: 'Hub Based API' +--- + + + +This page describes what used to be the "Unified API". +Previously, the Unified API was centered around a Hub as a central unit of control over the SDK. + +However, we are now moving away from the Hub-based API to a system centered around Scopes. + +Some SDKs (like the JavaScript SDK) have already moved to the new system, while others are in the process of transitioning. + +Read more about how to migrate away from Hubs in an SDK. + + + +## Motivation + +Sentry has a wide range of SDKs that have been developed over the years by different developers +and based on different ideas. This has lead to the situation that the feature sets across the +SDKs are different, use different concepts and terms which has lead to the situation that it's +often not clear how to achieve the same thing on different platforms. + +Additionally those SDKs were purely centered around error reporting through explicit clients which +meant that certain integrations (such as breadcrumbs) were often not possible. + +## General Guidelines + +- We want a unified language/wording of all SDK APIs to aid support and documentation as well as making it easier for users to use Sentry in different environments. + +- Design the SDK in a way where we can trivially add new features later that go past pure event reporting (transactions, APM etc.). + +- Design the SDK that with the same client instance we can both work naturally in the runtime environment through dependency injection etc. as well as using an implied context dispatching to already existing clients and scopes to hook into most environments. This is important because it allows events to include data from other integrations in the process. + +- The common tasks need to be easy and obvious. + +- For helping 3rd party libraries the case of “non configured Sentry” needs to be fast (and lazily executed). + +- The common API needs make sense in most languages and must not depend on super special constructs. To make it feel more natural we should consider language specifics and explicitly support them as alternatives (disposables, stack guards etc.). + +## Simplified Visualization + +![Unified API Visualized](./unified-api.png) + +## Terminology + +- **minimal**: A separate "facade" package that re-exports a subset of the SDK's functionality through interfaces or proxies. That package does not directly depend on the SDK, instead it should make every operation a noop if the SDK is not installed. + + The purpose of such a package is to allow random libraries to record breadcrumbs and set context data while not having a hard dependency on the SDK. + +- **hub**: An object that manages the state. An implied global thread local or similar hub exists that can be used by default. Hubs can be created manually. + +- **scope**: A scope holds data that should implicitly be sent with Sentry events. It can hold context data, extra parameters, level overrides, fingerprints etc. + +- **client**: A client is an object that is configured once and can be bound to the hub. The user can then auto discover the client and dispatch calls to it. Users typically do not need to work with the client directly. They either do it via the hub or static convenience functions. The client is mostly responsible for building Sentry events and dispatching those to the transport. + +- **client options**: Are parameters that are language and runtime specific and used to configure the client. This can be release and environment but also things like which integrations to configure, how in-app works etc. + +- **context**: Contexts give extra data to Sentry. There are the special contexts (user and similar) and the generic ones (`runtime`, `os`, `device`), etc. Check out Contexts for some predefined keys - users can also add arbitrary context keys. *Note: In older SDKs, you might encounter an unrelated concept of context, which is now deprecated by scopes* + +- **tags**: Tags can be arbitrary string→string pairs by which events can be searched. Contexts are converted into tags. + +- **extra**: Truly arbitrary data attached by client users. Extra should be avoided where possible, and instead structured `context` or `tags` should be used - as these can be queried and visualized in a better way. + +- **transport**: The transport is an internal construct of the client that abstracts away the event sending. Typically the transport runs in a separate thread and gets events to send via a queue. The transport is responsible for sending, retrying and handling rate limits. The transport might also persist unsent events across restarts if needed. + +- **integration**: Code that provides middlewares, bindings or hooks into certain frameworks or environments, along with code that inserts those bindings and activates them. Usage for integrations does not follow a common interface. + +- **event processors**: Callbacks that run for every event. + They can either modify and return the event, or `null`. + Returning `null` will discard the event and not process further. + + See [Event Pipeline](#event-pipeline) for more information. + +- **disabled SDK**: Most of the SDK functionality depends on a + configured and active client. + Sentry considers the client active when it has a *transport*. + Otherwise, the client is inactive, and the SDK is considered "disabled". + In this case, certain callbacks, such as `configure_scope` or + *event processors*, may not be invoked. + As a result, breadcrumbs are not recorded. + + +## "Static API" + +The static API functions is the most common user facing API. A user just imports these functions and can start +emitting events to Sentry or configuring scopes. These shortcut functions should be exported in the top-level +namespace of your package. Behind the scenes they use hubs and scopes (see [Concurrency](#concurrency) for more information) if available on that platform. +Note that all listed functions below are mostly aliases for `Hub::get_current().function`. + +- `init(options)`: This is the entry point for every SDK. + +This typically creates / reinitializes the global hub which is propagated to all new threads/execution contexts, or a hub is created per thread/execution context. + +Takes options (dsn etc.), configures a client and binds it to the current hub or initializes it. Should return a stand-in that can be used to drain events (a disposable). + +This might return a handle or guard for disposing. How this is implemented is entirely up to the SDK. This might even be a client if that’s something that makes sense for the SDK. In Rust it’s a ClientInitGuard, in JavaScript it could be a helper object with a close method that is awaitable. + +You should be able to call this multiple times where calling it a second time either tears down the previous client or decrements a refcount for the previous client etc. + +Calling this multiple times should be used for testing only. +It’s undefined what happens if you call `init` on anything but application startup. + +A user has to call `init` once but it’s permissible to call this with a disabled DSN of sorts. Might for instance be no parameter passed etc. + +Additionally it also sets up all default integrations. + +- `capture_event(event)`: Takes an already assembled event and dispatches it to the currently active hub. The event object can be a plain dictionary or a typed object whatever makes more sense in the SDK. It should follow the native protocol as close as possible ignoring platform specific renames (case styles etc.). + +- `capture_exception(error)`: Report an error or exception object. Depending on the platform different parameters are possible. The most obvious version accepts just an error object but also variations are possible where no error is passed and the current exception is used. + +- `capture_message(message, level)`: Reports a message. The level can be optional in language with default parameters in which case it should default to `info`. + +- `add_breadcrumb(crumb)`: Adds a new breadcrumb to the scope. If the total + number of breadcrumbs exceeds the `max_breadcrumbs` setting, the SDK should + remove the oldest breadcrumb. This works like the Hub API with regards to what + `crumb` can be. If the SDK is disabled, it should ignore the breadcrumb. + +- `configure_scope(callback)`: Calls a callback with a scope object that can be reconfigured. This is used to attach contextual data for future events in the same scope. + +- `last_event_id()`: Should return the last event ID emitted by the current scope. This is for instance used to implement user feedback dialogs. + +- `start_session()`: Stores a session on the current scope and starts tracking it. This normally attaches a brand new session to the scope, and implicitly ends any already existing session. + +- `end_session()`: Ends the session, setting an appropriate `status` and `duration`, and enqueues it for sending to Sentry. + +## Concurrency + +All SDKs should have the concept of concurrency safe context storage. What this means depends on the language. The basic idea is that a user of the SDK can call a method to safely provide additional context information for all events that are about to be recorded. + +This is implemented as a thread local stack in most languages, but in some (such as JavaScript) it might be global under the assumption that this is something that makes sense in the environment. + +Here are some common concurrency patterns: + +* **Thread bound hub**: In that pattern each thread gets its own "hub" which internally manages a stack of scopes. If that pattern is followed one thread (the one that calls `init()`) becomes the "main" hub which is used as the base for newly spawned threads which will get a hub that is based on the main hub (but otherwise independent). + +* **Internally scoped hub**: On some platforms such as .NET ambient data is available in which case the Hub can internally manage the scopes. + +* **Dummy hub**: On some platforms concurrency just doesn't inherently exist. In that case the hub might be entirely absent or just be a singleton without concurrency management. + +## Hub + +Under normal circumstances the hub consists of a stack of clients and scopes. + +The SDK maintains two variables: The *main hub* (a global variable) and the *current hub* (a variable local to the current thread or execution context, also sometimes known as async local or context local) + +- `Hub::new(client, scope)`: Creates a new hub with the given client and scope. The client can be reused between hubs. The scope should be owned by the hub (make a clone if necessary) + +- `Hub::new_from_top(hub)` / alternatively native constructor overloads: Creates a new hub by cloning the top stack of another hub. + +- `get_current_hub()` / `Hub::current()` / `Hub::get_current()`: Global function or static function to return the current (thread's) hub + +- `get_main_hub()` / `Hub::main()` / `Hub::get_main()`: In languages where the main thread is special ("Thread bound hub" model) this returns the main thread’s hub instead of the current thread’s hub. This might not exist in all languages. + +- `Hub::capture_event` / `Hub::capture_message` / `Hub::capture_exception` Capture message / exception call into capture event. `capture_event` merges the event passed with the scope data and dispatches to the client. As an additional argument it also takes a Hint. + + For the hint parameter see [hints](#hints). + +- `Hub::push_scope()`: Pushes a new scope layer that inherits the previous data. This should return a disposable or stack guard for languages where it makes sense. When the "internally scoped hub" concurrency model is used calls to this are often necessary as otherwise a scope might be accidentally incorrectly shared. + +- `Hub::with_scope(callback)` (optional): In Python this could be a context manager, in Ruby a block function. Pushes and pops a scope for integration work. + +- `Hub::pop_scope()` (optional): Only exists in languages without better resource management. Better to have this function on a return value of `push_scope` or to use `with_scope`. This is also sometimes called `pop_scope_unsafe` to indicate that this method should not be used directly. + +- `Hub::configure_scope(callback)`: Invokes the callback with a mutable reference to the scope for modifications. This can also be a `with` statement in languages that have it (Python). If no active client is bound to this hub, the SDK should not invoke the callback. + +- `Hub::add_breadcrumb(crumb, hint)`: Adds a breadcrumb to the current scope. + + - The argument supported should be: + - function that creates a breadcrumb + - an already created breadcrumb object + - a list of breadcrumbs (optional) + - In languages where we do not have a basic form of overloading only a raw breadcrumb object should be accepted. + + The SDK should ignore the breadcrumb if no active client is bound to this hub. + + For the hint parameter see [hints](#hints). + +- `Hub::client()` / `Hub::get_client()` (optional): Accessor or getter that returns the current client or `None`. + +- `Hub::bind_client(new_client)`: Binds a different client to the hub. If the hub is also the owner of the client that was created by `init` it needs to keep a reference to it still if the hub is the object responsible for disposing it. + +- `Hub::unbind_client()` (optional): Optional way to unbind for languages where `bind_client` does not accept nullables. + +- `Hub::last_event_id()`: Should return the last event ID emitted by the current scope. This is for instance used to implement user feedback dialogs. + +- `Hub::run(hub, callback)` `hub.run(callback)`, `run_in_hub(hub, callback)` (optional): Runs a callback with the hub bound as the current hub. + +### Scope + +A scope holds data that should implicitly be sent with Sentry events. It can hold context data, extra parameters, level overrides, fingerprints etc. + +The user can modify the current scope (to set extra, tags, current user) through the global function `configure_scope`. `configure_scope` takes a callback function to which it passes the current scope. + +The reason for this callback-based API is efficiency. If the SDK is disabled, +it should not invoke the callback, thus avoiding unnecessary work. + +```javascript +Sentry.configureScope(scope => + scope.setExtra("character_name", "Mighty Fighter")); +``` + +- `scope.set_user(user)`: Shallow merges user configuration (`email`, `username`, …). Removing user data is SDK-defined, either with a `remove_user` function or by passing nothing as data. + +- `scope.set_extra(key, value)`: Sets the extra key to an arbitrary value, overwriting a potential previous value. Removing a key is SDK-defined, either with a `remove_extra` function or by passing nothing as data. This is deprecated functionality and users should be encouraged to use contexts instead. + +- `scope.set_extras(extras)`: Sets an object with key/value pairs, convenience function instead of multiple `set_extra` calls. As with `set_extra` this is considered deprecated functionality. + +- `scope.set_tag(key, value)`: Sets the tag to a string value, overwriting a potential previous value. Removing a key is SDK-defined, either with a `remove_tag` function or by passing nothing as data. + +- `scope.set_tags(tags)`: Sets an object with key/value pairs, convenience function instead of multiple `set_tag` calls. + +- `scope.set_context(key, value)`: Sets the context key to a value, overwriting a potential previous value. Removing a key is SDK-defined, either with a `remove_context` function or by passing nothing as data. The types are sdk specified. + +- `scope.set_level(level)`: Sets the level of all events sent within this scope. + +- `scope.set_transaction(transaction_name)`: Sets the name of the current transaction. + +- `scope.set_fingerprint(fingerprint[])`: Sets the fingerprint to group specific events together + +- `scope.add_event_processor(processor)`: Registers an event processor function. It takes an event and returns a new event or `None` to drop it. This is the basis of many integrations. + +- `scope.add_error_processor(processor)` (optional): Registers an error processor function. It takes an event and exception object and returns a new event or `None` to drop it. This can be used to extract additional information out of an exception object that the SDK cannot extract itself. + +- `scope.clear()`: Resets a scope to default values while keeping all + registered event processors. This does not affect either child or parent scopes. + +- `scope.add_breadcrumb(breadcrumb)`: Adds a breadcrumb to the current scope. + +- `scope.clear_breadcrumbs()`: Deletes current breadcrumbs from the scope. + +- `scope.apply_to_event(event[, max_breadcrumbs])`: Applies the scope data to the given event object. This also applies the event processors stored in the scope internally. Some implementations might want to set a max breadcrumbs count here. + +## Client + +A Client is the part of the SDK that is responsible for event creation. To give an example, the Client should convert an exception to a Sentry event. The Client should be stateless, it gets the Scope injected and delegates the work of sending the event to the Transport. + +- `Client::from_config(config)`: (alternatively normal constructor) This takes typically an object with options + dsn. + +- `Client::capture_event(event, scope)`: Captures the event by merging it with other data with defaults from the client. In addition, if a scope is passed to this system, the data from the scope passes it to the internal transport. + +- `Client::close(timeout)`: Flushes out the queue for up to timeout seconds. If the client can guarantee delivery of events only up to the current point in time this is preferred. This might block for timeout seconds. The client should be disabled or disposed after close is called + +- `Client::flush(timeout)`: Same as `close` difference is that the client is NOT disposed after calling flush + +## Hints + +Optionally an additional parameter is supported to event capturing and breadcrumb adding: a hint. + +A hint is SDK specific but provides high level information about the origin of +the event. For instance if an exception was captured the hint might carry the +original exception object. Not all SDKs are required to provide this. The +parameter however is reserved for this purpose. + +## Event Pipeline + +An event captured by `capture_event` is processed in the following order. +**Note**: The event can be discarded at any of the stages, at which point no further +processing happens. + +1. If the SDK is disabled, Sentry discards the event right away. +2. The client samples events as defined by the configured sample rate. + Events may be discarded randomly, according to the sample rate. +3. The scope is applied, using `apply_to_event`. The scope’s *event processors* + are invoked in order. +4. Sentry invokes the *before-send* hook. +5. Sentry passes the event to the configured transport. + The transport can discard the event if it does not have a valid DSN; its + internal queue is full; or due to rate limiting, as requested by the server. + +## Options + +Many options are standardized across SDKs. For a list of these refer to [the main options documentation](https://docs.sentry.io/error-reporting/configuration/). diff --git a/src/docs/sdk/hub-based-api/unified-api.excalidraw b/src/docs/sdk/hub-based-api/unified-api.excalidraw new file mode 100644 index 0000000000..0526c95d73 --- /dev/null +++ b/src/docs/sdk/hub-based-api/unified-api.excalidraw @@ -0,0 +1,796 @@ +{ + "type": "excalidraw", + "version": 1, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "3qrrTZfINNLLc6KPzSIe5", + "type": "rectangle", + "x": 535.05859375, + "y": 349.3828125, + "width": 201.1640625, + "height": 129.2265625, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 2059412052, + "version": 159, + "versionNonce": 894658644, + "isDeleted": false + }, + { + "id": "D8SCAgr6FsN23HLJOKMet", + "type": "text", + "x": 552.67578125, + "y": 390.64453125, + "width": 164, + "height": 34, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 1202240364, + "version": 494, + "versionNonce": 1994573780, + "isDeleted": false, + "text": "Static API", + "font": "28px Cascadia", + "textAlign": "center", + "baseline": 27 + }, + { + "id": "8zlaJQnroS_bdx0IB9kOu", + "type": "text", + "x": 519.68359375, + "y": 325.12109375, + "width": 235, + "height": 20, + "angle": 0, + "strokeColor": "#5f3dc4", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 1133652972, + "version": 132, + "versionNonce": 5577196, + "isDeleted": false, + "text": "User Entry Point / Public API", + "font": "16px Virgil", + "textAlign": "center", + "baseline": 14 + }, + { + "id": "lIn7gig0vxn7USQVnv-pw", + "type": "rectangle", + "x": 535.19140625, + "y": 522.875, + "width": 201.1640625, + "height": 129.2265625, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 1396089964, + "version": 270, + "versionNonce": 241673812, + "isDeleted": false + }, + { + "id": "iPFO2eb42UnKozxmNvl7a", + "type": "text", + "x": 610.30859375, + "y": 564.13671875, + "width": 49, + "height": 34, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 474294356, + "version": 611, + "versionNonce": 682359148, + "isDeleted": false, + "text": "Hub", + "font": "28px Cascadia", + "textAlign": "center", + "baseline": 27 + }, + { + "id": "UNYMxoo4j7_hEpUW_HL1g", + "type": "arrow", + "x": 633.296875, + "y": 480.6171875, + "width": 1.4375, + "height": 38.80078125, + "angle": 0, + "strokeColor": "#5f3dc4", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 673782380, + "version": 283, + "versionNonce": 533790804, + "isDeleted": false, + "points": [ + [ + 0, + 0 + ], + [ + -1.4375, + 38.80078125 + ] + ], + "lastCommittedPoint": null + }, + { + "id": "o7UWhMo8dq-T4y2QWZ2pU", + "type": "text", + "x": 657.26953125, + "y": 500.28125, + "width": 77, + "height": 20, + "angle": 0, + "strokeColor": "#5f3dc4", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 1026058708, + "version": 56, + "versionNonce": 546222700, + "isDeleted": false, + "text": "The SDK", + "font": "16px Virgil", + "textAlign": "center", + "baseline": 14 + }, + { + "id": "I39fc5fWNUYNFRk-h9CVP", + "type": "rectangle", + "x": 323.375, + "y": 714.41015625, + "width": 201.1640625, + "height": 129.2265625, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 1970382572, + "version": 307, + "versionNonce": 130975060, + "isDeleted": false + }, + { + "id": "0h_EsmP2wCWmULcvM8Muh", + "type": "text", + "x": 373.9921875, + "y": 755.671875, + "width": 98, + "height": 34, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 286363092, + "version": 657, + "versionNonce": 1990960236, + "isDeleted": false, + "text": "Client", + "font": "28px Cascadia", + "textAlign": "center", + "baseline": 27 + }, + { + "id": "Q3LK7K8CsdxtFd9ecVt6Y", + "type": "rectangle", + "x": 751.69921875, + "y": 719.10546875, + "width": 201.1640625, + "height": 129.2265625, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 1010018004, + "version": 332, + "versionNonce": 1551987180, + "isDeleted": false + }, + { + "id": "g6M83zOXf9LSWWw5-tQb3", + "type": "text", + "x": 810.31640625, + "y": 760.3671875, + "width": 82, + "height": 34, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 257810540, + "version": 681, + "versionNonce": 373486700, + "isDeleted": false, + "text": "Scope", + "font": "28px Cascadia", + "textAlign": "center", + "baseline": 27 + }, + { + "id": "nYQDtinU4bPwIpD_cKVNs", + "type": "rectangle", + "x": 323.9921875, + "y": 926.56640625, + "width": 201.1640625, + "height": 129.2265625, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 295479508, + "version": 380, + "versionNonce": 482137812, + "isDeleted": false + }, + { + "id": "HQCeUCvXALRSFQy0izHta", + "type": "text", + "x": 349.609375, + "y": 967.828125, + "width": 148, + "height": 34, + "angle": 0, + "strokeColor": "#000000", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 1652424300, + "version": 742, + "versionNonce": 1369455956, + "isDeleted": false, + "text": "Transport", + "font": "28px Cascadia", + "textAlign": "center", + "baseline": 27 + }, + { + "id": "TCWwdAZlVotm3d0HFIp9h", + "type": "text", + "x": 323.88671875, + "y": 690.86328125, + "width": 105, + "height": 20, + "angle": 0, + "strokeColor": "#5f3dc4", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 347216852, + "version": 189, + "versionNonce": 1280075220, + "isDeleted": false, + "text": "Builds Events", + "font": "16px Virgil", + "textAlign": "center", + "baseline": 14 + }, + { + "id": "EBgjmEW0iSesbG7mkt3dC", + "type": "text", + "x": 843.4453125, + "y": 696.54296875, + "width": 109, + "height": 20, + "angle": 0, + "strokeColor": "#5f3dc4", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 291326700, + "version": 327, + "versionNonce": 387599724, + "isDeleted": false, + "text": "Holds context", + "font": "16px Virgil", + "textAlign": "center", + "baseline": 14 + }, + { + "id": "bZicz-MfeDeIR4M_gRUyS", + "type": "text", + "x": 421.0078125, + "y": 903.125, + "width": 104, + "height": 20, + "angle": 0, + "strokeColor": "#5f3dc4", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 4, + "roughness": 0, + "opacity": 100, + "seed": 20829012, + "version": 270, + "versionNonce": 1277143508, + "isDeleted": false, + "text": "Sends Events", + "font": "16px Virgil", + "textAlign": "center", + "baseline": 14 + }, + { + "id": "Z3XFb6ovUu0X4rFsTqkgs", + "type": "arrow", + "x": 746.546875, + "y": 715.09765625, + "width": 42.40625, + "height": 56.92578125, + "angle": 0, + "strokeColor": "#5f3dc4", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 568160596, + "version": 59, + "versionNonce": 1629277012, + "isDeleted": false, + "points": [ + [ + 0, + 0 + ], + [ + -42.40625, + -56.92578125 + ] + ], + "lastCommittedPoint": null + }, + { + "id": "dfQiAjC3AGvW0IKLkjx17", + "type": "arrow", + "x": 562.2265625, + "y": 659.91796875, + "width": 42.40234375, + "height": 48.24609375, + "angle": 0, + "strokeColor": "#5f3dc4", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 1651380716, + "version": 180, + "versionNonce": 968224364, + "isDeleted": false, + "points": [ + [ + 0, + 0 + ], + [ + -42.40234375, + 48.24609375 + ] + ], + "lastCommittedPoint": null + }, + { + "id": "KpeVQFm6Ja78yz_vKDrew", + "type": "arrow", + "x": 355.5121527777771, + "y": 849.7065972222215, + "width": 0.38671875, + "height": 69.19921875, + "angle": 0, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 2133897708, + "version": 104, + "versionNonce": 801041876, + "isDeleted": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.38671875, + 69.19921875 + ] + ], + "lastCommittedPoint": null + }, + { + "id": "mzbRuT3zALH5vybgsp6dV", + "type": "text", + "x": 318.58550347222194, + "y": 372.38671874999966, + "width": 197, + "height": 19, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 1947945068, + "version": 283, + "versionNonce": 1115983084, + "isDeleted": false, + "text": "e.g. captureMessage()", + "font": "16px Cascadia", + "textAlign": "center", + "baseline": 15 + }, + { + "id": "xRrKT4YHMckTHlHsfJ_m0", + "type": "arrow", + "x": 413.1584201388889, + "y": 406.8285590277777, + "width": 1.5525173611110858, + "height": 102.37065972222229, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 1853976684, + "version": 1073, + "versionNonce": 334457452, + "isDeleted": false, + "points": [ + [ + 0, + 0 + ], + [ + 1.5525173611110858, + 102.37065972222229 + ] + ], + "lastCommittedPoint": null + }, + { + "id": "Z4JpDECxUwk06gSZT1Ccm", + "type": "text", + "x": 272.3671875, + "y": 523.78515625, + "width": 253, + "height": 19, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 716437356, + "version": 475, + "versionNonce": 1997504596, + "isDeleted": false, + "text": "getCurrentHub().getClient()", + "font": "16px Cascadia", + "textAlign": "center", + "baseline": 15 + }, + { + "id": "SOB6n6jdQ91-EWiReaYIc", + "type": "arrow", + "x": 400.74913194444446, + "y": 553.6171875, + "width": 156.46788194444446, + "height": 149.41796875, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 1813251540, + "version": 688, + "versionNonce": 822953196, + "isDeleted": false, + "points": [ + [ + 0, + 0 + ], + [ + -156.46788194444446, + 149.41796875 + ] + ], + "lastCommittedPoint": null + }, + { + "id": "keD-eEvlLxmthcsF4uLbH", + "type": "text", + "x": 152.44921875, + "y": 716.65234375, + "width": 150, + "height": 19, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 785293548, + "version": 408, + "versionNonce": 722760172, + "isDeleted": false, + "text": "captureMessage()", + "font": "16px Cascadia", + "textAlign": "center", + "baseline": 15 + }, + { + "id": "vpUsAc-0bsh-k8FMce2Vu", + "type": "arrow", + "x": 236.17730034722223, + "y": 746.9331597222222, + "width": 0.45876736111108585, + "height": 168.59027777777783, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 1630891604, + "version": 1235, + "versionNonce": 2046521708, + "isDeleted": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.45876736111108585, + 168.59027777777783 + ] + ], + "lastCommittedPoint": null + }, + { + "id": "T1H9e1vQU9ZxwHzpoj6Zd", + "type": "text", + "x": 183.07421875000006, + "y": 930.4166666666654, + "width": 103, + "height": 19, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 1590749908, + "version": 511, + "versionNonce": 204931668, + "isDeleted": false, + "text": "sendEvent()", + "font": "16px Cascadia", + "textAlign": "center", + "baseline": 15 + }, + { + "id": "vZQrtY9rRmdLbNnvCMd3r", + "type": "text", + "x": 193.4244791666663, + "y": 583.0972222222213, + "width": 145, + "height": 40, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 1500684780, + "version": 286, + "versionNonce": 35291476, + "isDeleted": false, + "text": "Hub passes scope \nto client", + "font": "16px Virgil", + "textAlign": "center", + "baseline": 34 + }, + { + "id": "fHx64-LJymubfAQsjQHhn", + "type": "text", + "x": 34.35677083333337, + "y": 799.8116319444445, + "width": 191, + "height": 40, + "angle": 0, + "strokeColor": "#1864ab", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 968432492, + "version": 320, + "versionNonce": 248667604, + "isDeleted": false, + "text": "Client applies scope and\nbuilds an event", + "font": "16px Virgil", + "textAlign": "center", + "baseline": 34 + }, + { + "id": "zT7r5L3f3IQDdZDRYvoYp", + "type": "arrow", + "x": 853.8064236111111, + "y": 683.8307291666667, + "width": 20.468750000000114, + "height": 20.785590277777942, + "angle": 0, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 1624805972, + "version": 265, + "versionNonce": 1456339412, + "isDeleted": false, + "points": [ + [ + 0, + 0 + ], + [ + -20.468750000000114, + -20.785590277777942 + ] + ], + "lastCommittedPoint": null + }, + { + "id": "VyMS4kBYw5lFIOTS2YcgA", + "type": "text", + "x": 786.0963541666661, + "y": 537.9322916666672, + "width": 112, + "height": 120, + "angle": 0, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 1241057108, + "version": 349, + "versionNonce": 990088300, + "isDeleted": false, + "text": "- Breadcrumbs\n- Extra\n- Tags\n- User\n- Level\n....", + "font": "16px Virgil", + "textAlign": "left", + "baseline": 114 + }, + { + "id": "9HnhE8jRX0u_JTU-3-ysO", + "type": "text", + "x": 782.9722222222227, + "y": 266.33420138888835, + "width": 71, + "height": 25, + "angle": 0, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 2104832468, + "version": 473, + "versionNonce": 1041646700, + "isDeleted": false, + "text": "Options", + "font": "20px Virgil", + "textAlign": "left", + "baseline": 18 + }, + { + "id": "2yFB3wT9XsLDHer8NE-pB", + "type": "arrow", + "x": 819.2361111111111, + "y": 296.4947916666667, + "width": 68.79340277777771, + "height": 76.04600694444446, + "angle": 0, + "strokeColor": "#087f5b", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "roughness": 1, + "opacity": 100, + "seed": 2075483244, + "version": 181, + "versionNonce": 1931150956, + "isDeleted": false, + "points": [ + [ + 0, + 0 + ], + [ + -16.740451388888914, + 64.44010416666663 + ], + [ + -68.79340277777771, + 76.04600694444446 + ] + ], + "lastCommittedPoint": [ + -68.79340277777771, + 76.04600694444446 + ] + } + ], + "appState": { + "viewBackgroundColor": "#ffffff" + } +} \ No newline at end of file diff --git a/src/docs/sdk/hub-based-api/unified-api.png b/src/docs/sdk/hub-based-api/unified-api.png new file mode 100644 index 0000000000000000000000000000000000000000..b35df07a0cc790e2c1c05aa4d528fd78a379f5dd GIT binary patch literal 101906 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

    T6sM=;*LaTIr#f!vs$IqI*ZqUZk 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 & Scope Refactoring +* *Types Example:* Typed languages might have very different developer experience than dynamic. +* *Platform Example:* Does Rust have exceptions? Nope, don't name APIs for rust like `captureException`. +Until recently, the unified API was centered around the concept of a `Hub`. Some SDKs are still using this concept, but it is being phased out in favor of the new scope-based approach lined out in this document. Read about the Hub based API. New Sentry SDKs should follow the unified API, use consistent terms to refer to concepts. This @@ -45,25 +43,19 @@ meant that certain integrations (such as breadcrumbs) were often not possible. ## Simplified Visualization -![Unified API Visualized](./unified-api.png) +TODO: Graphic of the SDK pieces interacting ## Terminology -- **minimal**: A separate "facade" package that re-exports a subset of the SDK's functionality through interfaces or proxies. That package does not directly depend on the SDK, instead it should make every operation a noop if the SDK is not installed. - - The purpose of such a package is to allow random libraries to record breadcrumbs and set context data while not having a hard dependency on the SDK. - -- **hub**: An object that manages the state. An implied global thread local or similar hub exists that can be used by default. Hubs can be created manually. +- **scope**: A scope holds data that should implicitly be sent with Sentry events. It can hold context data, extra parameters, level overrides, fingerprints etc. You should read the user-facing [documentation on Scopes](https://docs.sentry.io/platforms/javascript/enriching-events/scopes/) before continuing. -- **scope**: A scope holds data that should implicitly be sent with Sentry events. It can hold context data, extra parameters, level overrides, fingerprints etc. - -- **client**: A client is an object that is configured once and can be bound to the hub. The user can then auto discover the client and dispatch calls to it. Users typically do not need to work with the client directly. They either do it via the hub or static convenience functions. The client is mostly responsible for building Sentry events and dispatching those to the transport. +- **client**: A client is an object that is configured once and is bound to a scope. The user can then auto discover the client and dispatch calls to it. Users typically do not need to work with the client directly, they should generally use top-level methods that may call the client under the hood. The client is mostly responsible for building Sentry events and dispatching those to the transport. - **client options**: Are parameters that are language and runtime specific and used to configure the client. This can be release and environment but also things like which integrations to configure, how in-app works etc. -- **context**: Contexts give extra data to Sentry. There are the special contexts (user and similar) and the generic ones (`runtime`, `os`, `device`), etc. Check out Contexts for some predefined keys - users can also add arbitrary context keys. *Note: In older SDKs, you might encounter an unrelated concept of context, which is now deprecated by scopes* +- **context**: Contexts give extra data to Sentry. There are the custom contexts (set by the user) and predefined ones (e.g. `runtime`, `os`, `device`). Check out Contexts for some predefined keys. -- **tags**: Tags can be arbitrary string→string pairs by which events can be searched. Contexts are converted into tags. +- **tags**: Tags can be arbitrary string→string pairs by which events can be searched. - **extra**: Truly arbitrary data attached by client users. Extra should be avoided where possible, and instead structured `context` should be used - as these can be queried and visualized in a better way. @@ -73,7 +65,7 @@ meant that certain integrations (such as breadcrumbs) were often not possible. - **event processors**: Callbacks that run for every event. They can either modify and return the event, or `null`. - Returning `null` will discard the event and not process further. + When `null` is returned, the SDK MUST discard the event and not process it further. See [Event Pipeline](#event-pipeline) for more information. @@ -81,128 +73,211 @@ meant that certain integrations (such as breadcrumbs) were often not possible. configured and active client. Sentry considers the client active when it has a *transport*. Otherwise, the client is inactive, and the SDK is considered "disabled". - In this case, certain callbacks, such as `configure_scope` or - *event processors*, may not be invoked. - As a result, breadcrumbs are not recorded. - + In this case, the SDK MUST NOT send any events, and SHOULD NOT register any (global) handlers. -## "Static API" +## Static API (or Top-Level API) The static API functions is the most common user facing API. A user just imports these functions and can start emitting events to Sentry or configuring scopes. These shortcut functions should be exported in the top-level -namespace of your package. Behind the scenes they use hubs and scopes (see [Concurrency](#concurrency) for more information) if available on that platform. -Note that all listed functions below are mostly aliases for `Hub::get_current().function`. +namespace of your package. Behind the scenes they use scopes and clients (see [Concurrency](#concurrency) for more information). -- `init(options)`: This is the entry point for every SDK. +The static APIs should cover the 95% use case for a common user. They should be easy to use and understand, and should be considered the primary way users interact with the Sentry SDK. -This typically creates / reinitializes the global hub which is propagated to all new threads/execution contexts, or a hub is created per thread/execution context. +### `init(options)` -Takes options (dsn etc.), configures a client and binds it to the current hub or initializes it. Should return a stand-in that can be used to drain events (a disposable). +This is the entry point for every SDK. Every SDK MUST have an `init` method. Calling `init` will create & setup a new client, and bind it to the current scope. -This might return a handle or guard for disposing. How this is implemented is entirely up to the SDK. This might even be a client if that’s something that makes sense for the SDK. In Rust it’s a ClientInitGuard, in JavaScript it could be a helper object with a close method that is awaitable. +The options passed in are SDK specific, but typically include a DSN, release, environment, etc. -You should be able to call this multiple times where calling it a second time either tears down the previous client or decrements a refcount for the previous client etc. +This method SHOULD return a stand-in that can be used to drain events (a disposable), or the created client. +It SHOULD be possible to call `init` multiple times, where calling it a second time either tears down the previous client or decrements a refcount for the previous client etc. Calling this multiple times should be used for testing only. It’s undefined what happens if you call `init` on anything but application startup. -A user has to call `init` once but it’s permissible to call this with a disabled DSN of sorts. Might for instance be no parameter passed etc. +A user has to call `init` once but it’s permissible to call this with a disabled DSN of sorts. In this case, the SDK will be *disabled*. -Additionally it also sets up all default integrations. +Calling `init` MUST set up all default & defined integrations, UNLESS the SDK is disabled. When the SDK is disabled, it SHOULD NOT set up any integrations. -- `capture_event(event)`: Takes an already assembled event and dispatches it to the currently active hub. The event object can be a plain dictionary or a typed object whatever makes more sense in the SDK. It should follow the native protocol as close as possible ignoring platform specific renames (case styles etc.). +### `get_client()` -- `capture_exception(error)`: Report an error or exception object. Depending on the platform different parameters are possible. The most obvious version accepts just an error object but also variations are possible where no error is passed and the current exception is used. +Returns the currently active client. This MAY return `null` if `init` was never called. If `init` was called but the SDK is disabled, this SHOULD return the disabled client. -- `capture_message(message, level)`: Reports a message. The level can be optional in language with default parameters in which case it should default to `info`. +Instead of retuning `null` if the SDK was never initialized, this method MAY return a disabled (or a no-op) client. -- `add_breadcrumb(crumb)`: Adds a new breadcrumb to the scope. If the total - number of breadcrumbs exceeds the `max_breadcrumbs` setting, the SDK should - remove the oldest breadcrumb. This works like the Hub API with regards to what - `crumb` can be. If the SDK is disabled, it should ignore the breadcrumb. +### `capture_event(event)` -- `configure_scope(callback)`: Calls a callback with a scope object that can be reconfigured. This is used to attach contextual data for future events in the same scope. +Takes an already assembled event and dispatches it to the current scope. -- `last_event_id()`: Should return the last event ID emitted by the current scope. This is for instance used to implement user feedback dialogs. +This SHOULD be equivalent to calling `get_current_scope().capture_event(event)`. -- `start_session()`: Stores a session on the current scope and starts tracking it. This normally attaches a brand new session to the scope, and implicitly ends any already existing session. +The event object can be a plain dictionary or a typed object whatever makes more sense in the SDK. +It should follow the native protocol as close as possible ignoring platform specific renames (case styles etc.). -- `end_session()`: Ends the session, setting an appropriate `status` and `duration`, and enqueues it for sending to Sentry. +### `capture_exception(error)` -## Concurrency +Report an error or exception object and dispatches it to the current scope. -All SDKs should have the concept of concurrency safe context storage. What this means depends on the language. The basic idea is that a user of the SDK can call a method to safely provide additional context information for all events that are about to be recorded. +This SHOULD be equivalent to calling `get_current_scope().capture_exception(error)`. -This is implemented as a thread local stack in most languages, but in some (such as JavaScript) it might be global under the assumption that this is something that makes sense in the environment. +Depending on the platform different parameters are possible. +The most obvious version accepts just an error object but also variations are possible where no error is passed and the current exception is used. -Here are some common concurrency patterns: +### `capture_message(message, level)` -* **Thread bound hub**: In that pattern each thread gets its own "hub" which internally manages a stack of scopes. If that pattern is followed one thread (the one that calls `init()`) becomes the "main" hub which is used as the base for newly spawned threads which will get a hub that is based on the main hub (but otherwise independent). +Reports a message and dispatches it to the current scope. -* **Internally scoped hub**: On some platforms such as .NET ambient data is available in which case the Hub can internally manage the scopes. +This SHOULD be equivalent to calling `get_current_scope().capture_message(message)`. -* **Dummy hub**: On some platforms concurrency just doesn't inherently exist. In that case the hub might be entirely absent or just be a singleton without concurrency management. +The level can be optional in language with default parameters in which case it should default to `info`. -## Hub +### `add_breadcrumb(crumb)` -Under normal circumstances the hub consists of a stack of clients and scopes. +Adds a new breadcrumb to the isolation scope. If the totalnumber of breadcrumbs exceeds the `max_breadcrumbs` setting, the SDK should remove the oldest breadcrumb. -The SDK maintains two variables: The *main hub* (a global variable) and the *current hub* (a variable local to the current thread or execution context, also sometimes known as async local or context local) +This SHOULD be equivalent to calling `get_isolation_scope().add_breadcrumb(crumb)`. -- `Hub::new(client, scope)`: Creates a new hub with the given client and scope. The client can be reused between hubs. The scope should be owned by the hub (make a clone if necessary) +If the SDK is disabled, it SHOULD ignore the breadcrumb. -- `Hub::new_from_top(hub)` / alternatively native constructor overloads: Creates a new hub by cloning the top stack of another hub. +### `set_tag(key, value)` -- `get_current_hub()` / `Hub::current()` / `Hub::get_current()`: Global function or static function to return the current (thread's) hub +Set a tag on the isolation scope. -- `get_main_hub()` / `Hub::main()` / `Hub::get_main()`: In languages where the main thread is special ("Thread bound hub" model) this returns the main thread’s hub instead of the current thread’s hub. This might not exist in all languages. +This SHOULD be equivalent to calling `get_isolation_scope().set_tag(key, value)`. -- `Hub::capture_event` / `Hub::capture_message` / `Hub::capture_exception` Capture message / exception call into capture event. `capture_event` merges the event passed with the scope data and dispatches to the client. As an additional argument it also takes a Hint. +### `set_context(name, context)` - For the hint parameter see [hints](#hints). +Set a context on the isolation scope. -- `Hub::push_scope()`: Pushes a new scope layer that inherits the previous data. This should return a disposable or stack guard for languages where it makes sense. When the "internally scoped hub" concurrency model is used calls to this are often necessary as otherwise a scope might be accidentally incorrectly shared. +This SHOULD be equivalent to calling `get_isolation_scope().set_context(name, context)`. -- `Hub::with_scope(callback)` (optional): In Python this could be a context manager, in Ruby a block function. Pushes and pops a scope for integration work. +### `set_extra(key, value)` -- `Hub::pop_scope()` (optional): Only exists in languages without better resource management. Better to have this function on a return value of `push_scope` or to use `with_scope`. This is also sometimes called `pop_scope_unsafe` to indicate that this method should not be used directly. +Set extra data on the isolation scope. -- `Hub::configure_scope(callback)`: Invokes the callback with a mutable reference to the scope for modifications. This can also be a `with` statement in languages that have it (Python). If no active client is bound to this hub, the SDK should not invoke the callback. +This SHOULD be equivalent to calling `get_isolation_scope().set_extra(key, value)`. -- `Hub::add_breadcrumb(crumb, hint)`: Adds a breadcrumb to the current scope. +### `set_user(user)` - - The argument supported should be: - - function that creates a breadcrumb - - an already created breadcrumb object - - a list of breadcrumbs (optional) - - In languages where we do not have a basic form of overloading only a raw breadcrumb object should be accepted. +Set the user on the isolation scope. - The SDK should ignore the breadcrumb if no active client is bound to this hub. +This SHOULD be equivalent to calling `get_isolation_scope().set_user(user)`. - For the hint parameter see [hints](#hints). +If `null` is passed in, the user SHOULD be reset. -- `Hub::client()` / `Hub::get_client()` (optional): Accessor or getter that returns the current client or `None`. +### `with_scope(callback)` -- `Hub::bind_client(new_client)`: Binds a different client to the hub. If the hub is also the owner of the client that was created by `init` it needs to keep a reference to it still if the hub is the object responsible for disposing it. +Creates a new current scope that is active for the duration of the callback. +This is useful for attaching contextual data to a subset of events that is dispatched inside of the provided callback. -- `Hub::unbind_client()` (optional): Optional way to unbind for languages where `bind_client` does not accept nullables. +The callback MUST receive the new scope as an argument. The new scope MUST be forked from the current scope, and the current scope MUST be restored after the callback is executed. -- `Hub::last_event_id()`: Should return the last event ID emitted by the current scope. This is for instance used to implement user feedback dialogs. +Mutating the new scope MUST NOT affect the previous current scope. -- `Hub::run(hub, callback)` `hub.run(callback)`, `run_in_hub(hub, callback)` (optional): Runs a callback with the hub bound as the current hub. +### `with_isolation_scope(callback)` -### Scope +Creates a new isolation scope that is active for the duration of the callback. +This is useful for attaching contextual data to a subset of events that is dispatched inside of the provided callback. -A scope holds data that should implicitly be sent with Sentry events. It can hold context data, extra parameters, level overrides, fingerprints etc. +The callback MUST receive the new isolation scope as an argument. The new isolation scope MUST be forked from the current isolation scope, and the current isolation scope MUST be restored after the callback is executed. + +Mutating the new isolation scope MUST NOT affect the previous isolation scope. + +This method MAY also fork the current scope (similar to `with_scope`) in addition to forking the isolation scope. + +### `get_current_scope()` + +Returns the currently active scope. This is the scope that is used for all events that are dispatched. + +### `get_isolation_scope()` + +Returns the currently active isolation scope. This is the scope that is used to store breadcrumbs and contextual data that should be attached to events. + +### `get_global_scope()` + +Returns the global scope, which is applied to all events dispatched by the SDK. This scope MUST be a singleton and shared across all instances of the SDK. + +### `last_event_id()` + +Returns the last event ID that was emitted. The last event ID SHOULD be kept on the isolation scope, and thus SHOULD be kept per isolated process. This is for instance used to implement user feedback dialogs. + +### `start_session()` + +Stores a session on the current scope and starts tracking it. This SHOULD attach a brand new session to the isolation scope, and implicitly ends any already existing session. + +### `end_session()` + +Ends the session, setting an appropriate `status` and `duration`, and enqueues it for sending to Sentry. + +## Concurrency + +All SDKs SHOULD have the concept of concurrency safe context storage, if the language permits it. What this means depends on the language. + +The goal is that, wherever possible, concurrent operations can be automatically isolated from each other, in order to prevent data to leak between different operations. +A classic example for this is to isolate requests in a HTTP server - if a user sets a user in this request, it should be applied to any event captured in this request, but not to events captured in other requests (because they may have a different user). + +The SDK SHOULD automatically manage this isolation, so that the user does not have to worry about it. For cases where the SDK cannot do that automatically, the SDK MUST provide a way for the user to manually manage the isolation (for example via `with_isolation_scope()`). -The user can modify the current scope (to set extra, tags, current user) through the global function `configure_scope`. `configure_scope` takes a callback function to which it passes the current scope. +In client-side applications (Browser JS or mobile), there MAY not be a way to isolate code from each other. In this case, the SDK MAY fall back to handling state globally. -The reason for this callback-based API is efficiency. If the SDK is disabled, -it should not invoke the callback, thus avoiding unnecessary work. +This is implemented as a thread local stack in most languages, or as a different construct (e.g. async local storage in Node.js) in others. + +### How to store concurrency data + +Each thread local SHOULD hold a reference to the current scope & isolation scope that is active for the current thread. +Newly spawned threads SHOULD inherit the reference to the isolation scope from the parent thread, and SHOULD create a new scope that is a child of the parent current scope, and make this the current scope for the child thread. + +The isolation scope MAY be forked (instead of using the same reference) for a new thread if the SDK identifies that the new thread is a new logical operation that should not share data with the parent thread. +For example, if the new thread is a new HTTP request in a server, it SHOULD have a new isolation scope. + +In some environments it MAY be necessary to retrospectively change the isolation scope - for example, when it is not possible to know at the time of thread spawning if the new thread should be isolated. +In this case, the SDK MAY retrospectively update the isolation scope on the thread local. + +```javascript +const initialCurrentScope = getCurrentScope(); +const initialIsolationScope = getIsolationScope(); + +myApp.get('/my-route', function() { + // current scope is a fork of initialCurrentScope + assert(getCurrentScope() !== initialCurrentScope); + // This is a HTTP route handler, which we want to isolate from other routes + // So the isolation scope is a fork of the initialIsolationScope + assert(getIsolationScope() !== initialIsolationScope); +}); +``` + +Calling `with_scope` or `with_isolation_scope` SHOULD spawn a new thread local that is active for the duration of the callback, and SHOULD restore the previous thread local after the callback is executed. + +### Environments without process isolation + +In environments that do not support process isolation (e.g. Browser JS), the isolation scope should be considered a singleton, similar to the global scope. +In this case, `with_isolation_scope` SHOULD NOT fork the isolation scope, but instead just keep the current isolation scope. + +The current scope MAY be kept as a simple stack that is pushed and popped as needed. This stack MAY not be async safe, and may leak between different parts of the code. This should be avoided, if possible. ```javascript -Sentry.configureScope(scope => - scope.setExtra("character_name", "Mighty Fighter")); +const initialCurrentScope = getCurrentScope(); +const initialIsolationScope = getIsolationScope(); + +document.querySelector('#my-button').addEventListener('click', function() { + Sentry.withScope(scope => { + assert(getCurrentScope() !== initialCurrentScope); + assert(getIsolationScope() === initialIsolationScope); + // scope is valid until the end of this callback + // there are no guarantees that scope may not bleed outside of this callback + }); +}); +``` + +## Scope + +A scope holds data that should implicitly be sent with Sentry events. It can hold context data, extra parameters, level overrides, fingerprints etc. + +The user can modify the current scope (to set extra, tags, current user) directly, but the main way for users to interact with the scope is through the [Static API](#static-api-or-top-level-api). + +```javascript +const scope = Sentry.getCurrentScope(); +scope.setExtra("character_name", "Mighty Fighter")); ``` - `scope.set_user(user)`: Shallow merges user configuration (`email`, `username`, …). Removing user data is SDK-defined, either with a `remove_user` function or by passing nothing as data. @@ -232,9 +307,20 @@ Sentry.configureScope(scope => - `scope.add_breadcrumb(breadcrumb)`: Adds a breadcrumb to the current scope. -- `scope.clear_breadcrumbs()`: Deletes current breadcrumbs from the scope. +- `scope.clear_breadcrumbs()` (optional): Deletes current breadcrumbs from the scope. + +- `scope.capture_exception(exception)`: Capture an exception, ensuring the scope's data is added to the event. + +- `scope.capture_message(message)`: Capture a message, ensuring the scope's data is added to the event. + +- `scope.capture_event(event)`: Capture an event, ensuring the scope's data is added to the event. -- `scope.apply_to_event(event[, max_breadcrumbs])`: Applies the scope data to the given event object. This also applies the event processors stored in the scope internally. Some implementations might want to set a max breadcrumbs count here. +A client MAY have a scope attached to it. Generally, the global & isolation scopes SHOULD NOT have a client attached, but only the current scope. +The client is inherited by child scopes. This way, each current scope (which is used to capture events) knows which client it should route events to. + +## Applying Scope Data to Events + +See [user-facing Scope Docs](https://docs.sentry.io/platforms/javascript/enriching-events/scopes/) on details about how scopes should be applied. ## Client @@ -248,6 +334,17 @@ A Client is the part of the SDK that is responsible for event creation. To give - `Client::flush(timeout)`: Same as `close` difference is that the client is NOT disposed after calling flush +When `get_client` is called, it SHOULD return the client that is currently bound to the current scope. +If no client is bound to the current scope, it SHOULD either return `null`, or a Non-Recording (disabled) client. + +## `get_current_hub()` (Legacy) + +Previously, users interacted with the SDK through a `Hub` object. This object was responsible for managing the current scope, client, and other SDK state. + +While we do not have a hub anymore, we want to keep providing a `get_current_hub()` API for backwards compatibility. +This method SHOULD return a shim or similar that allows to keep using old hub methods. This SHOULD NOT exist in new SDKs, but only in SDKs that are transitioning from the old hub-based API to the new scope-based API. +All methods that can be shimmed SHOULD continue to be available. Methods (like `push_scope` or `pop_scope`) that cannot be shimmed MAY be removed or MAY no-op. + ## Hints Optionally an additional parameter is supported to event capturing and breadcrumb adding: a hint. From 318dee7886a97fb51d35e8755459945f9085c3d5 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Wed, 19 Jun 2024 16:37:54 +0200 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> --- src/docs/sdk/unified-api/index.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/docs/sdk/unified-api/index.mdx b/src/docs/sdk/unified-api/index.mdx index 7dbf17842d..52c478c0a0 100644 --- a/src/docs/sdk/unified-api/index.mdx +++ b/src/docs/sdk/unified-api/index.mdx @@ -47,7 +47,7 @@ TODO: Graphic of the SDK pieces interacting ## Terminology -- **scope**: A scope holds data that should implicitly be sent with Sentry events. It can hold context data, extra parameters, level overrides, fingerprints etc. You should read the user-facing [documentation on Scopes](https://docs.sentry.io/platforms/javascript/enriching-events/scopes/) before continuing. +- **scope**: A scope holds data that should implicitly be sent with Sentry events. It can hold context data, extra parameters, level overrides, fingerprints etc. There are three different scopes (global, isolation and current). To understand scopes and the differences between those you should read the user-facing [documentation on Scopes](https://docs.sentry.io/platforms/javascript/enriching-events/scopes/) before continuing. - **client**: A client is an object that is configured once and is bound to a scope. The user can then auto discover the client and dispatch calls to it. Users typically do not need to work with the client directly, they should generally use top-level methods that may call the client under the hood. The client is mostly responsible for building Sentry events and dispatching those to the transport. @@ -78,7 +78,7 @@ TODO: Graphic of the SDK pieces interacting ## Static API (or Top-Level API) The static API functions is the most common user facing API. A user just imports these functions and can start -emitting events to Sentry or configuring scopes. These shortcut functions should be exported in the top-level +emitting events to Sentry or configuring scopes. These shortcut functions should be exported in the top-level namespace of your package. Behind the scenes they use scopes and clients (see [Concurrency](#concurrency) for more information). The static APIs should cover the 95% use case for a common user. They should be easy to use and understand, and should be considered the primary way users interact with the Sentry SDK. @@ -129,7 +129,7 @@ Reports a message and dispatches it to the current scope. This SHOULD be equivalent to calling `get_current_scope().capture_message(message)`. -The level can be optional in language with default parameters in which case it should default to `info`. +The level can be optional in languages with default parameters in which case it should default to `info`. ### `add_breadcrumb(crumb)`