Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### New Features

- Added `sentry::read_scope` and `Hub::read_scope`, read-only counterparts to [`configure_scope`](https://docs.rs/sentry-core/0.48.4/sentry_core/fn.configure_scope.html) that avoid cloning the scope and writing it back. The `sentry-tracing` integration now uses this to resolve the parent span when creating a new span.

## 0.48.4

### New Features
Expand Down
22 changes: 22 additions & 0 deletions sentry-core/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,28 @@ where
Hub::with_active(|hub| hub.configure_scope(f))
}

/// Invokes a function with read-only access to the current scope.
///
/// The function is passed a shared reference to the [`Scope`]. Because there
/// might currently not be a scope or client active it's possible that the
/// callback might not be called at all. As a result of this the return value
/// of this closure must have a default that is returned in such cases.
///
/// # Examples
///
/// ```
/// # sentry::test::with_captured_events(|| {
/// let span = sentry::read_scope(|scope| scope.get_span());
/// # });
/// ```
pub fn read_scope<F, R>(f: F) -> R
where
R: Default,
F: FnOnce(&Scope) -> R,
{
Hub::with_active(|hub| hub.read_scope(f))
}

/// Temporarily pushes a scope for a single call optionally reconfiguring it.
///
/// This function takes two arguments: the first is a callback that is passed
Expand Down
18 changes: 18 additions & 0 deletions sentry-core/src/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,24 @@ impl Hub {
}
}

/// Invokes a function with read-only access to the current scope.
///
/// See the global [`read_scope`](crate::read_scope)
/// for more documentation.
pub fn read_scope<F, R>(&self, f: F) -> R
where
R: Default,
F: FnOnce(&Scope) -> R,
{
use_without_client!(f);
with_client_impl! {{
// Clone the `Arc<Scope>` out so the callback runs without
// holding the stack lock, keeping reentrant hub calls safe.
let scope = self.inner.with(|stack| stack.top().scope.clone());
f(&scope)
}}
}

/// Invokes a function that can modify the current scope.
///
/// See the global [`configure_scope`](fn.configure_scope.html)
Expand Down
2 changes: 1 addition & 1 deletion sentry-tracing/src/layer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ where
sentry_op.unwrap_or_else(|| format!("{}::{}", span.metadata().target(), span.name()));

let hub = sentry_core::Hub::current();
let parent_sentry_span = hub.configure_scope(|scope| scope.get_span());
let parent_sentry_span = hub.read_scope(|scope| scope.get_span());

let mut sentry_span: sentry_core::TransactionOrSpan = match &parent_sentry_span {
Some(parent) => parent.start_child(&sentry_op, sentry_name).into(),
Expand Down
4 changes: 2 additions & 2 deletions sentry/examples/performance-demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn main_span1() {
let transaction_ctx = sentry::TransactionContext::continue_from_span(
"background transaction",
"root span",
sentry::configure_scope(|scope| scope.get_span()),
sentry::read_scope(|scope| scope.get_span()),
);
thread::spawn(move || {
let transaction = sentry::start_transaction(transaction_ctx);
Expand Down Expand Up @@ -76,7 +76,7 @@ fn wrap_in_span<F, R>(op: &str, description: &str, f: F) -> R
where
F: FnOnce() -> R,
{
let parent = sentry::configure_scope(|scope| scope.get_span());
let parent = sentry::read_scope(|scope| scope.get_span());
let span1: sentry::TransactionOrSpan = match &parent {
Some(parent) => parent.start_child(op, description).into(),
None => {
Expand Down
20 changes: 17 additions & 3 deletions sentry/tests/test_basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ fn test_event_trace_context_from_propagation_context() {
let mut last_event_id = None::<Uuid>;
let mut span = None;
let events = sentry::test::with_captured_events(|| {
sentry::configure_scope(|scope| {
span = scope.get_span();
});
span = sentry::read_scope(|scope| scope.get_span());
sentry::capture_message("Hello World!", sentry::Level::Warning);
last_event_id = sentry::last_event_id();
});
Expand Down Expand Up @@ -160,6 +158,22 @@ fn test_reentrant_configure_scope() {
assert_eq!(events[0].tags["which_scope"], "scope1");
}

#[test]
fn test_reentrant_read_scope() {
let events = sentry::test::with_captured_events(|| {
sentry::read_scope(|_scope| {
sentry::configure_scope(|scope| {
scope.set_tag("which_scope", "reentrant");
});
});

sentry::capture_message("look ma, no deadlock!", sentry::Level::Info);
});

assert_eq!(events.len(), 1);
assert_eq!(events[0].tags["which_scope"], "reentrant");
}

#[test]
fn test_attached_stacktrace() {
let logger = sentry_log::SentryLogger::new();
Expand Down
Loading