Skip to content

Commit 180a6b1

Browse files
fix(sentry-tracing): switch sentry spans on enter and exit (#686)
--------- Co-authored-by: DoumanAsh <[email protected]>
1 parent 00cb40f commit 180a6b1

File tree

4 files changed

+57
-11
lines changed

4 files changed

+57
-11
lines changed

sentry-core/src/hub_impl.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@ thread_local! {
2121
);
2222
}
2323

24-
pub(crate) struct SwitchGuard {
24+
/// A Hub switch guard used to temporarily swap
25+
/// active hub in thread local storage.
26+
pub struct SwitchGuard {
2527
inner: Option<(Arc<Hub>, bool)>,
2628
}
2729

2830
impl SwitchGuard {
29-
pub(crate) fn new(mut hub: Arc<Hub>) -> Self {
31+
/// Swaps the current thread's Hub by the one provided
32+
/// and returns a guard that, when dropped, replaces it
33+
/// to the previous one.
34+
pub fn new(mut hub: Arc<Hub>) -> Self {
3035
let inner = THREAD_HUB.with(|(thread_hub, is_process_hub)| {
3136
// SAFETY: `thread_hub` will always be a valid thread local hub,
3237
// by definition not shared between threads.

sentry-core/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,9 @@ pub mod metrics;
149149
mod session;
150150
#[cfg(all(feature = "client", feature = "metrics"))]
151151
mod units;
152+
152153
#[cfg(feature = "client")]
153-
pub use crate::client::Client;
154+
pub use crate::{client::Client, hub_impl::SwitchGuard as HubSwitchGuard};
154155

155156
// test utilities
156157
#[cfg(feature = "test")]

sentry-core/src/performance.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,12 @@ impl Span {
717717
transaction.context.clone()
718718
}
719719

720+
/// Get the current span ID.
721+
pub fn get_span_id(&self) -> protocol::SpanId {
722+
let span = self.span.lock().unwrap();
723+
span.span_id
724+
}
725+
720726
/// Get the status of the Span.
721727
pub fn get_status(&self) -> Option<protocol::SpanStatus> {
722728
let span = self.span.lock().unwrap();

sentry-tracing/src/layer.rs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::borrow::Cow;
22
use std::cell::RefCell;
33
use std::collections::BTreeMap;
4+
use std::sync::Arc;
45

56
use sentry_core::protocol::Value;
67
use sentry_core::{Breadcrumb, TransactionOrSpan};
@@ -197,6 +198,8 @@ fn record_fields<'a, K: AsRef<str> + Into<Cow<'a, str>>>(
197198
pub(super) struct SentrySpanData {
198199
pub(super) sentry_span: TransactionOrSpan,
199200
parent_sentry_span: Option<TransactionOrSpan>,
201+
hub: Arc<sentry_core::Hub>,
202+
hub_switch_guard: Option<sentry_core::HubSwitchGuard>,
200203
}
201204

202205
impl<S> Layer<S> for SentryLayer<S>
@@ -256,7 +259,9 @@ where
256259
}
257260
});
258261

259-
let parent_sentry_span = sentry_core::configure_scope(|s| s.get_span());
262+
let hub = sentry_core::Hub::current();
263+
let parent_sentry_span = hub.configure_scope(|scope| scope.get_span());
264+
260265
let sentry_span: sentry_core::TransactionOrSpan = match &parent_sentry_span {
261266
Some(parent) => parent.start_child(op, &description).into(),
262267
None => {
@@ -268,15 +273,48 @@ where
268273
// This comes from typically the `fields` in `tracing::instrument`.
269274
record_fields(&sentry_span, data);
270275

271-
sentry_core::configure_scope(|scope| scope.set_span(Some(sentry_span.clone())));
272-
273276
let mut extensions = span.extensions_mut();
274277
extensions.insert(SentrySpanData {
275278
sentry_span,
276279
parent_sentry_span,
280+
hub,
281+
hub_switch_guard: None,
277282
});
278283
}
279284

285+
/// Sets entered span as *current* sentry span. A tracing span can be
286+
/// entered and existed multiple times, for example, when using a `tracing::Instrumented` future.
287+
fn on_enter(&self, id: &span::Id, ctx: Context<'_, S>) {
288+
let span = match ctx.span(id) {
289+
Some(span) => span,
290+
None => return,
291+
};
292+
293+
let mut extensions = span.extensions_mut();
294+
if let Some(data) = extensions.get_mut::<SentrySpanData>() {
295+
data.hub_switch_guard = Some(sentry_core::HubSwitchGuard::new(data.hub.clone()));
296+
data.hub.configure_scope(|scope| {
297+
scope.set_span(Some(data.sentry_span.clone()));
298+
})
299+
}
300+
}
301+
302+
/// Set exited span's parent as *current* sentry span.
303+
fn on_exit(&self, id: &span::Id, ctx: Context<'_, S>) {
304+
let span = match ctx.span(id) {
305+
Some(span) => span,
306+
None => return,
307+
};
308+
309+
let mut extensions = span.extensions_mut();
310+
if let Some(data) = extensions.get_mut::<SentrySpanData>() {
311+
data.hub.configure_scope(|scope| {
312+
scope.set_span(data.parent_sentry_span.clone());
313+
});
314+
data.hub_switch_guard.take();
315+
}
316+
}
317+
280318
/// When a span gets closed, finish the underlying sentry span, and set back
281319
/// its parent as the *current* sentry span.
282320
fn on_close(&self, id: span::Id, ctx: Context<'_, S>) {
@@ -286,16 +324,12 @@ where
286324
};
287325

288326
let mut extensions = span.extensions_mut();
289-
let SentrySpanData {
290-
sentry_span,
291-
parent_sentry_span,
292-
} = match extensions.remove::<SentrySpanData>() {
327+
let SentrySpanData { sentry_span, .. } = match extensions.remove::<SentrySpanData>() {
293328
Some(data) => data,
294329
None => return,
295330
};
296331

297332
sentry_span.finish();
298-
sentry_core::configure_scope(|scope| scope.set_span(parent_sentry_span));
299333
}
300334

301335
/// Implement the writing of extra data to span

0 commit comments

Comments
 (0)