Scopes and Hubs
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.
When an event is captured and sent to Sentry, SDKs will merge that event data with extra information from the current scope. SDKs will typically automatically manage the scopes for you in the framework integrations and you don't need to think about them. However, you should know what a scope is and how you can use it for your advantage.
You can think of the hub as the central point that our SDKs use to route an event to Sentry. When you call init()
a hub is created and a client and a blank scope are created on it. That hub is then associated with the current thread and will internally hold a stack of scopes.
The scope will hold useful information that should be sent along with the event. For instance contexts or breadcrumbs are stored on the scope. When a scope is pushed, it inherits all data from the parent scope and when it pops all modifications are reverted.
The default SDK integrations will push and pop scopes intelligently. For instance web framework integrations will create and destroy scopes around your routes or controllers.
As you start using an SDK, a scope and hub are automatically created for you out of the box. It's unlikely that you'll interact with the hub directly unless you're writing an integration or you want to create or destroy scopes. Scopes, on the other hand are more user facing. You can call configure_scope
at any point in time to modify data stored on the scope. This is useful for doing things like modifying the context.
When you call a global function such as capture_event
internally Sentry discovers the current hub and asks it to capture an event. Internally the hub will then merge the event with the topmost scope's data.
Hub Abstraction Is Not Implemented
The Native SDK currently only provides a single scope shared by all threads in the program and maintains no thread-local state by way of a hub. Because of this limitation, you must make sure that your threads don't logically interfere with each other's changes to the global scope, even though they are safe to do so purely from a data-race perspective. This affects use cases where, for example, you want to track many users in server-like programs while capturing events or when you want to trace multiple threads in tracing.
For details on how this affects tracing, check out the Connect Errors With Spans section of "Custom Instrumentation".
The most useful operation when working with scopes is the configure_scope
function. It can be used to reconfigure the current scope.
You can, for instance, add custom tags or inform Sentry about the currently authenticated user.
The Native SDK maintains all data in a single global scope.
#include <sentry.h>
sentry_set_tag("my-tag", "my value");
sentry_value_t user = sentry_value_new_object();
sentry_value_set_by_key(user, "id", sentry_value_new_int32(42));
sentry_value_set_by_key(user, "email", sentry_value_new_string("john.doe@example.com"));
sentry_set_user(user);
You can also apply this configuration when unsetting a user at logout:
sentry_remove_user();
To learn what useful information can be associated with scopes see the context documentation.
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").