Skip to content

Commit

Permalink
Add hub switch guard to the tracing layer
Browse files Browse the repository at this point in the history
  • Loading branch information
DoumanAsh authored and saiintbrisson committed Nov 28, 2024
1 parent 3501378 commit f537a94
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 20 deletions.
7 changes: 7 additions & 0 deletions sentry-core/src/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use std::sync::{Arc, RwLock};

use crate::hub_impl::SwitchGuard;
use crate::protocol::{Event, Level, SessionStatus};
use crate::types::Uuid;
use crate::{Integration, IntoBreadcrumbs, Scope, ScopeGuard};
Expand Down Expand Up @@ -242,4 +243,10 @@ impl Hub {
})
}}
}

#[inline(always)]
/// Consumes self to create switch guard, that can be used to modify current hub in thread local storage
pub fn into_switch_guard(self: Arc<Hub>) -> SwitchGuard {
crate::hub_impl::SwitchGuard::new(self)
}
}
5 changes: 4 additions & 1 deletion sentry-core/src/hub_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ thread_local! {
);
}

pub(crate) struct SwitchGuard {
///Hub switch guard
///
///Used to temporarily swap active hub in thread local storage.
pub struct SwitchGuard {
inner: Option<(Arc<Hub>, bool)>,
}

Expand Down
1 change: 1 addition & 0 deletions sentry-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ pub use crate::clientoptions::{BeforeCallback, ClientOptions, SessionMode};
pub use crate::error::{capture_error, event_from_error, parse_type_from_debug};
pub use crate::futures::{SentryFuture, SentryFutureExt};
pub use crate::hub::Hub;
pub use crate::hub_impl::SwitchGuard as HubSwitchGuard;
pub use crate::integration::Integration;
pub use crate::intodsn::IntoDsn;
pub use crate::performance::*;
Expand Down
43 changes: 24 additions & 19 deletions sentry-tracing/src/layer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::sync::Arc;

use sentry_core::protocol::Value;
use sentry_core::{Breadcrumb, TransactionOrSpan};
Expand Down Expand Up @@ -197,6 +198,8 @@ fn record_fields<'a, K: AsRef<str> + Into<Cow<'a, str>>>(
pub(super) struct SentrySpanData {
pub(super) sentry_span: TransactionOrSpan,
parent_sentry_span: Option<TransactionOrSpan>,
hub: Arc<sentry_core::Hub>,
hub_switch_guard: Option<sentry_core::HubSwitchGuard>,
}

impl<S> Layer<S> for SentryLayer<S>
Expand Down Expand Up @@ -256,7 +259,9 @@ where
}
});

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

let sentry_span: sentry_core::TransactionOrSpan = match &parent_sentry_span {
Some(parent) => parent.start_child(op, &description).into(),
None => {
Expand All @@ -272,42 +277,42 @@ where
extensions.insert(SentrySpanData {
sentry_span,
parent_sentry_span,
hub,
hub_switch_guard: None,
});
}

/// Sets entered span as *current* sentry span. A tracing span can be
/// entered and existed multiple times, for example, when using a `tracing::Instrumented` future.
fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
let span = match ctx.span(&id) {
let span = match ctx.span(id) {
Some(span) => span,
None => return,
};

let extensions = span.extensions();
let SentrySpanData { sentry_span, .. } = match extensions.get::<SentrySpanData>() {
Some(data) => data,
None => return,
};

sentry_core::configure_scope(|scope| scope.set_span(Some(sentry_span.clone())));
let mut extensions = span.extensions_mut();
if let Some(data) = extensions.get_mut::<SentrySpanData>() {
data.hub_switch_guard = Some(data.hub.clone().into_switch_guard());
data.hub.configure_scope(|scope| {
scope.set_span(Some(data.sentry_span.clone()));
})
}
}

/// Set exited span's parent as *current* sentry span.
fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
let span = match ctx.span(&id) {
let span = match ctx.span(id) {
Some(span) => span,
None => return,
};

let extensions = span.extensions();
let SentrySpanData {
parent_sentry_span, ..
} = match extensions.get::<SentrySpanData>() {
Some(data) => data,
None => return,
};

sentry_core::configure_scope(|scope| scope.set_span(parent_sentry_span.clone()));
let mut extensions = span.extensions_mut();
if let Some(data) = extensions.get_mut::<SentrySpanData>() {
data.hub.configure_scope(|scope| {
scope.set_span(data.parent_sentry_span.clone());
});
data.hub_switch_guard = None;
}
}

/// When a span gets closed, finish the underlying sentry span, and set back
Expand Down

0 comments on commit f537a94

Please sign in to comment.