diff --git a/relay-event-normalization/src/normalize/span/tag_extraction.rs b/relay-event-normalization/src/normalize/span/tag_extraction.rs index b0726014241..6720781d7d8 100644 --- a/relay-event-normalization/src/normalize/span/tag_extraction.rs +++ b/relay-event-normalization/src/normalize/span/tag_extraction.rs @@ -505,8 +505,10 @@ pub fn extract_tags( } if let Some(measurements) = span.measurements.value() { if span_op.starts_with("ui.interaction.") && measurements.contains_key("inp") { - if let Some(transaction) = - span.data.value().and_then(|data| data.transaction.as_str()) + if let Some(transaction) = span + .data + .value() + .and_then(|data| data.segment_name.as_str()) { span_tags.insert(SpanTagKey::Transaction, transaction.into()); } @@ -572,13 +574,8 @@ pub fn extract_tags( } } - if let Some(browser_name) = span - .data - .value() - .and_then(|data| data.browser_name.value()) - .and_then(|browser_name| browser_name.as_str()) - { - span_tags.insert(SpanTagKey::BrowserName, browser_name.into()); + if let Some(browser_name) = span.data.value().and_then(|data| data.browser_name.value()) { + span_tags.insert(SpanTagKey::BrowserName, browser_name.clone()); } span_tags diff --git a/relay-event-schema/src/protocol/span.rs b/relay-event-schema/src/protocol/span.rs index badf42f49f7..d24424feb64 100644 --- a/relay-event-schema/src/protocol/span.rs +++ b/relay-event-schema/src/protocol/span.rs @@ -165,7 +165,7 @@ pub struct SpanData { /// The client's browser name. #[metastructure(field = "browser.name")] - pub browser_name: Annotated, + pub browser_name: Annotated, /// The source code file name that identifies the code unit as uniquely as possible. #[metastructure(field = "code.filepath", pii = "maybe")] @@ -271,10 +271,13 @@ pub struct SpanData { #[metastructure(field = "thread.name")] pub thread_name: Annotated, - /// Origin Transaction name of the span. + /// Name of the segment that this span belongs to (see `segment_id`). + /// + /// This corresponds to the transaction name in the transaction-based model. /// /// For INP spans, this is the route name where the interaction occurred. - pub transaction: Annotated, + #[metastructure(field = "segment.name", legacy_alias = "transaction")] + pub segment_name: Annotated, /// Name of the UI component (e.g. React). #[metastructure(field = "ui.component_name")] @@ -292,6 +295,10 @@ pub struct SpanData { #[metastructure(field = "replay_id")] pub replay_id: Annotated, + /// The sentry SDK (see [`crate::protocol::ClientSdkInfo`]). + #[metastructure(field = "sdk.name")] + pub sdk_name: Annotated, + /// Other fields in `span.data`. #[metastructure(additional_properties, pii = "true", retain = "true")] other: Object, @@ -301,7 +308,7 @@ impl Getter for SpanData { fn get_value(&self, path: &str) -> Option> { Some(match path { "app_start_type" => self.app_start_type.value()?.into(), - "browser\\.name" => self.browser_name.value()?.into(), + "browser\\.name" => self.browser_name.as_str()?.into(), "code\\.filepath" => self.code_filepath.value()?.into(), "code\\.function" => self.code_function.value()?.into(), "code\\.lineno" => self.code_lineno.value()?.into(), @@ -327,7 +334,7 @@ impl Getter for SpanData { "thread\\.name" => self.thread_name.value()?.into(), "ui\\.component_name" => self.ui_component_name.value()?.into(), "url\\.scheme" => self.url_scheme.value()?.into(), - "transaction" => self.transaction.as_str()?.into(), + "transaction" => self.segment_name.as_str()?.into(), _ => { let escaped = path.replace("\\.", "\0"); let mut path = escaped.split('.').map(|s| s.replace('\0', ".")); @@ -529,11 +536,12 @@ mod tests { ai_total_tokens_used: ~, ai_responses: ~, thread_name: ~, - transaction: ~, + segment_name: ~, ui_component_name: ~, url_scheme: ~, user: ~, replay_id: ~, + sdk_name: ~, other: { "bar": String( "3", diff --git a/relay-event-schema/src/protocol/span/convert.rs b/relay-event-schema/src/protocol/span/convert.rs index f2c5ac1dd39..ecf449d2f71 100644 --- a/relay-event-schema/src/protocol/span/convert.rs +++ b/relay-event-schema/src/protocol/span/convert.rs @@ -1,5 +1,5 @@ //! This module defines bidirectional field mappings between spans and transactions. -use crate::protocol::{Contexts, Event, ProfileContext, Span, TraceContext}; +use crate::protocol::{BrowserContext, Contexts, Event, ProfileContext, Span, TraceContext}; use relay_base_schema::events::EventType; use relay_protocol::Annotated; @@ -40,15 +40,18 @@ macro_rules! context_write_path ( ); macro_rules! event_write_path( + ($event:expr, contexts browser $context_field:ident) => { + context_write_path!($event, BrowserContext, $context_field) + }; ($event:expr, contexts trace $context_field:ident) => { context_write_path!($event, TraceContext, $context_field) }; ($event:expr, contexts profile $context_field:ident) => { context_write_path!($event, ProfileContext, $context_field) }; - ($event:expr, $path_root:ident $(. $path_segment:ident)*) => { + ($event:expr, $path_root:ident $($path_segment:ident)*) => { { - write_path!($event, $path_root $(. $path_segment:ident)*) + write_path!($event, $path_root $($path_segment)*) } }; ); @@ -63,17 +66,20 @@ macro_rules! context_value ( ); macro_rules! event_value( + ($event:expr, contexts browser $context_field:ident) => { + context_value!($event, BrowserContext, $context_field) + }; ($event:expr, contexts trace $context_field:ident) => { context_value!($event, TraceContext, $context_field) }; ($event:expr, contexts profile $context_field:ident) => { context_value!($event, ProfileContext, $context_field) }; - ($event:expr, $path_root:ident $(. $path_segment:ident)*) => { + ($event:expr, $path_root:ident $($path_segment:ident)*) => { { let value = ($event).$path_root.value(); $( - let value = value.and_then(|value|&value.$path_segment.value()); + let value = value.and_then(|value|value.$path_segment.value()); )* value } @@ -137,6 +143,7 @@ macro_rules! map_fields { map_fields!( span._metrics_summary <=> event._metrics_summary, span.description <=> event.transaction, + span.data.segment_name <=> event.transaction, span.measurements <=> event.measurements, span.platform <=> event.platform, span.received <=> event.received, @@ -153,7 +160,9 @@ map_fields!( span.trace_id <=> event.contexts.trace.trace_id, span.profile_id <=> event.contexts.profile.profile_id, span.data.release <=> event.release, - span.data.environment <=> event.environment + span.data.environment <=> event.environment, + span.data.browser_name <=> event.contexts.browser.name, + span.data.sdk_name <=> event.client_sdk.name ; span.is_segment <= true, span.was_transaction <= true @@ -165,6 +174,8 @@ map_fields!( mod tests { use relay_protocol::Annotated; + use crate::protocol::SpanData; + use super::*; #[test] @@ -172,9 +183,13 @@ mod tests { let event = Annotated::::from_json( r#"{ "type": "transaction", + "platform": "php", + "sdk": {"name": "sentry.php"}, "release": "myapp@1.0.0", "environment": "prod", + "transaction": "my 1st transaction", "contexts": { + "browser": {"name": "Chrome"}, "profile": {"profile_id": "a0aaaaaaaaaaaaaaaaaaaaaaaaaaaaab"}, "trace": { "trace_id": "4C79F60C11214EB38604F4AE0781BFB2", @@ -217,7 +232,7 @@ mod tests { timestamp: ~, start_timestamp: ~, exclusive_time: 123.4, - description: ~, + description: "my 1st transaction", op: "myop", span_id: SpanId( "fa90fdead5f74052", @@ -240,7 +255,7 @@ mod tests { ), data: SpanData { app_start_type: ~, - browser_name: ~, + browser_name: "Chrome", code_filepath: ~, code_lineno: ~, code_function: ~, @@ -266,11 +281,12 @@ mod tests { ai_total_tokens_used: ~, ai_responses: ~, thread_name: ~, - transaction: ~, + segment_name: "my 1st transaction", ui_component_name: ~, url_scheme: ~, user: ~, replay_id: ~, + sdk_name: "sentry.php", other: {}, }, sentry_tags: ~, @@ -300,7 +316,7 @@ mod tests { ], }, ), - platform: ~, + platform: "php", was_transaction: true, other: {}, } @@ -310,6 +326,23 @@ mod tests { assert_eq!(event, roundtripped); } + #[test] + fn segment_name_takes_precedence_over_description() { + let span = Span { + is_segment: true.into(), + description: "This is the description".to_owned().into(), + data: SpanData { + segment_name: "This is the segment name".to_owned().into(), + ..Default::default() + } + .into(), + ..Default::default() + }; + let event = Event::try_from(&span).unwrap(); + + assert_eq!(event.transaction.as_str(), Some("This is the segment name")); + } + #[test] fn no_empty_profile_context() { let span = Span { diff --git a/relay-server/src/metrics_extraction/snapshots/relay_server__metrics_extraction__event__tests__extract_span_metrics_mobile.snap b/relay-server/src/metrics_extraction/snapshots/relay_server__metrics_extraction__event__tests__extract_span_metrics_mobile.snap index 7aa673ccb77..9de0b77f1cb 100644 --- a/relay-server/src/metrics_extraction/snapshots/relay_server__metrics_extraction__event__tests__extract_span_metrics_mobile.snap +++ b/relay-server/src/metrics_extraction/snapshots/relay_server__metrics_extraction__event__tests__extract_span_metrics_mobile.snap @@ -339,11 +339,12 @@ expression: "(&event.value().unwrap().spans, metrics)" ai_total_tokens_used: ~, ai_responses: ~, thread_name: ~, - transaction: ~, + segment_name: ~, ui_component_name: ~, url_scheme: ~, user: ~, replay_id: ~, + sdk_name: ~, other: {}, }, sentry_tags: { @@ -421,11 +422,12 @@ expression: "(&event.value().unwrap().spans, metrics)" ai_total_tokens_used: ~, ai_responses: ~, thread_name: ~, - transaction: ~, + segment_name: ~, ui_component_name: ~, url_scheme: ~, user: ~, replay_id: ~, + sdk_name: ~, other: {}, }, sentry_tags: { diff --git a/relay-server/src/services/processor/span/processing.rs b/relay-server/src/services/processor/span/processing.rs index dc1f58c2c91..f8b80f1d293 100644 --- a/relay-server/src/services/processor/span/processing.rs +++ b/relay-server/src/services/processor/span/processing.rs @@ -484,7 +484,7 @@ fn normalize( .and_then(|v| v.name.value()) { let data = span.data.value_mut().get_or_insert_with(SpanData::default); - data.browser_name = Annotated::new(browser_name.to_owned().into()); + data.browser_name = Annotated::new(browser_name.to_owned()); } if let Annotated(Some(ref mut measurement_values), ref mut meta) = span.measurements { @@ -504,7 +504,7 @@ fn normalize( .data .value_mut() .as_mut() - .map(|data| &mut data.transaction) + .map(|data| &mut data.segment_name) { normalize_transaction_name(transaction, &project_config.tx_name_rules); }