From a138e3cd2fd69d0c9e75a1c0a079871af7980233 Mon Sep 17 00:00:00 2001 From: Luiz Carvalho Date: Wed, 25 Sep 2024 14:05:14 -0300 Subject: [PATCH] fix(sentry-tracing): switch sentry spans on enter and exit --- Cargo.lock | 26 +++++++++--------- sentry-core/src/performance.rs | 42 +++++++++++++++++++++++++++++ sentry-tracing/src/layer.rs | 48 +++++++++++++++++++++++++++------ sentry-types/src/protocol/v7.rs | 6 +++++ 4 files changed, 101 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d24421f7..c96b66a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3717,7 +3717,7 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "sentry" -version = "0.33.0" +version = "0.34.0" dependencies = [ "actix-web", "anyhow", @@ -3755,7 +3755,7 @@ dependencies = [ [[package]] name = "sentry-actix" -version = "0.33.0" +version = "0.34.0" dependencies = [ "actix-web", "futures", @@ -3767,7 +3767,7 @@ dependencies = [ [[package]] name = "sentry-anyhow" -version = "0.33.0" +version = "0.34.0" dependencies = [ "anyhow", "sentry", @@ -3777,7 +3777,7 @@ dependencies = [ [[package]] name = "sentry-backtrace" -version = "0.33.0" +version = "0.34.0" dependencies = [ "backtrace", "once_cell", @@ -3787,7 +3787,7 @@ dependencies = [ [[package]] name = "sentry-contexts" -version = "0.33.0" +version = "0.34.0" dependencies = [ "hostname", "libc", @@ -3800,7 +3800,7 @@ dependencies = [ [[package]] name = "sentry-core" -version = "0.33.0" +version = "0.34.0" dependencies = [ "anyhow", "cadence", @@ -3823,7 +3823,7 @@ dependencies = [ [[package]] name = "sentry-debug-images" -version = "0.33.0" +version = "0.34.0" dependencies = [ "findshlibs", "once_cell", @@ -3832,7 +3832,7 @@ dependencies = [ [[package]] name = "sentry-log" -version = "0.33.0" +version = "0.34.0" dependencies = [ "log", "pretty_env_logger", @@ -3842,7 +3842,7 @@ dependencies = [ [[package]] name = "sentry-panic" -version = "0.33.0" +version = "0.34.0" dependencies = [ "sentry", "sentry-backtrace", @@ -3851,7 +3851,7 @@ dependencies = [ [[package]] name = "sentry-slog" -version = "0.33.0" +version = "0.34.0" dependencies = [ "erased-serde", "sentry", @@ -3863,7 +3863,7 @@ dependencies = [ [[package]] name = "sentry-tower" -version = "0.33.0" +version = "0.34.0" dependencies = [ "anyhow", "axum 0.7.5", @@ -3883,7 +3883,7 @@ dependencies = [ [[package]] name = "sentry-tracing" -version = "0.33.0" +version = "0.34.0" dependencies = [ "log", "sentry", @@ -3897,7 +3897,7 @@ dependencies = [ [[package]] name = "sentry-types" -version = "0.33.0" +version = "0.34.0" dependencies = [ "debugid", "hex", diff --git a/sentry-core/src/performance.rs b/sentry-core/src/performance.rs index 062899ae..735a01f0 100644 --- a/sentry-core/src/performance.rs +++ b/sentry-core/src/performance.rs @@ -322,6 +322,24 @@ impl TransactionOrSpan { } } + #[doc(hidden)] + #[must_use = "a span must be explicitly closed via `finish()`"] + pub fn start_child_with_span_id( + &self, + op: &str, + description: &str, + span_id: protocol::SpanId, + ) -> Span { + match self { + TransactionOrSpan::Transaction(transaction) => { + transaction.start_child_with_span_id(op, description, span_id) + } + TransactionOrSpan::Span(span) => { + span.start_child_with_span_id(op, description, span_id) + } + } + } + #[cfg(feature = "client")] pub(crate) fn apply_to_event(&self, event: &mut protocol::Event<'_>) { if event.contexts.contains_key("trace") { @@ -587,10 +605,22 @@ impl Transaction { /// The span must be explicitly finished via [`Span::finish`]. #[must_use = "a span must be explicitly closed via `finish()`"] pub fn start_child(&self, op: &str, description: &str) -> Span { + self.start_child_with_span_id(op, description, Default::default()) + } + + #[doc(hidden)] + #[must_use = "a span must be explicitly closed via `finish()`"] + pub fn start_child_with_span_id( + &self, + op: &str, + description: &str, + span_id: protocol::SpanId, + ) -> Span { let inner = self.inner.lock().unwrap(); let span = protocol::Span { trace_id: inner.context.trace_id, parent_span_id: Some(inner.context.span_id), + span_id, op: Some(op.into()), description: if description.is_empty() { None @@ -754,10 +784,22 @@ impl Span { /// The span must be explicitly finished via [`Span::finish`]. #[must_use = "a span must be explicitly closed via `finish()`"] pub fn start_child(&self, op: &str, description: &str) -> Span { + self.start_child_with_span_id(op, description, Default::default()) + } + + #[doc(hidden)] + #[must_use = "a span must be explicitly closed via `finish()`"] + pub fn start_child_with_span_id( + &self, + op: &str, + description: &str, + span_id: protocol::SpanId, + ) -> Span { let span = self.span.lock().unwrap(); let span = protocol::Span { trace_id: span.trace_id, parent_span_id: Some(span.span_id), + span_id, op: Some(op.into()), description: if description.is_empty() { None diff --git a/sentry-tracing/src/layer.rs b/sentry-tracing/src/layer.rs index 8183bbfc..a23d1060 100644 --- a/sentry-tracing/src/layer.rs +++ b/sentry-tracing/src/layer.rs @@ -208,8 +208,11 @@ where }); let parent_sentry_span = sentry_core::configure_scope(|s| s.get_span()); + let span_id = sentry_core::protocol::SpanId::from(id.into_u64().to_ne_bytes()); let sentry_span: sentry_core::TransactionOrSpan = match &parent_sentry_span { - Some(parent) => parent.start_child(op, &description).into(), + Some(parent) => parent + .start_child_with_span_id(op, &description, span_id) + .into(), None => { let ctx = sentry_core::TransactionContext::new(&description, op); sentry_core::start_transaction(ctx).into() @@ -221,8 +224,6 @@ where sentry_span.set_data(key, value); } - sentry_core::configure_scope(|scope| scope.set_span(Some(sentry_span.clone()))); - let mut extensions = span.extensions_mut(); extensions.insert(SentrySpanData { sentry_span, @@ -230,6 +231,41 @@ where }); } + /// 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) { + Some(span) => span, + None => return, + }; + + let extensions = span.extensions(); + let SentrySpanData { sentry_span, .. } = match extensions.get::() { + Some(data) => data, + None => return, + }; + + sentry_core::configure_scope(|scope| scope.set_span(Some(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) { + Some(span) => span, + None => return, + }; + + let extensions = span.extensions(); + let SentrySpanData { + parent_sentry_span, .. + } = match extensions.get::() { + Some(data) => data, + None => return, + }; + + sentry_core::configure_scope(|scope| scope.set_span(parent_sentry_span.clone())); + } + /// When a span gets closed, finish the underlying sentry span, and set back /// its parent as the *current* sentry span. fn on_close(&self, id: span::Id, ctx: Context<'_, S>) { @@ -239,16 +275,12 @@ where }; let mut extensions = span.extensions_mut(); - let SentrySpanData { - sentry_span, - parent_sentry_span, - } = match extensions.remove::() { + let SentrySpanData { sentry_span, .. } = match extensions.remove::() { Some(data) => data, None => return, }; sentry_span.finish(); - sentry_core::configure_scope(|scope| scope.set_span(parent_sentry_span)); } /// Implement the writing of extra data to span diff --git a/sentry-types/src/protocol/v7.rs b/sentry-types/src/protocol/v7.rs index a2fc3a88..08bd2725 100644 --- a/sentry-types/src/protocol/v7.rs +++ b/sentry-types/src/protocol/v7.rs @@ -1355,6 +1355,12 @@ impl From for String { } } +impl From<[u8; 8]> for SpanId { + fn from(span_id: [u8; 8]) -> Self { + Self(span_id) + } +} + impl str::FromStr for SpanId { type Err = hex::FromHexError;