diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fd3e32602..858b13cafc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Drop `event_id` and `remote_addr` from all outcomes. ([#3319](https://github.com/getsentry/relay/pull/3319)) - Support for AI token metrics ([#3250](https://github.com/getsentry/relay/pull/3250)) - Accept integers in `event.user.username`. ([#3328](https://github.com/getsentry/relay/pull/3328)) +- Extract `cache.item_size` and `cache.hit` data into span indexed ([#3367]https://github.com/getsentry/relay/pull/3367) **Internal**: diff --git a/relay-event-normalization/src/normalize/span/tag_extraction.rs b/relay-event-normalization/src/normalize/span/tag_extraction.rs index 2fbcfa374f..797ef3ec44 100644 --- a/relay-event-normalization/src/normalize/span/tag_extraction.rs +++ b/relay-event-normalization/src/normalize/span/tag_extraction.rs @@ -66,6 +66,7 @@ pub enum SpanTagKey { /// The start type of the application when the span occurred. AppStartType, ReplayId, + CacheHit, } impl SpanTagKey { @@ -104,6 +105,7 @@ impl SpanTagKey { SpanTagKey::TimeToInitialDisplay => "ttid", SpanTagKey::FileExtension => "file_extension", SpanTagKey::MainThread => "main_thread", + SpanTagKey::CacheHit => "cache.hit", SpanTagKey::OsName => "os.name", SpanTagKey::AppStartType => "app_start_type", SpanTagKey::ReplayId => "replay_id", @@ -406,6 +408,15 @@ pub fn extract_tags( } } + if span_op.starts_with("cache.") { + if let Some(Value::Bool(cache_hit)) = + span.data.value().and_then(|data| data.cache_hit.value()) + { + let tag_value = if *cache_hit { "true" } else { "false" }; + span_tags.insert(SpanTagKey::CacheHit, tag_value.to_owned()); + } + } + if let Some(scrubbed_desc) = scrubbed_description { // Truncating the span description's tag value is, for now, // a temporary solution to not get large descriptions dropped. The @@ -559,6 +570,27 @@ pub fn extract_measurements(span: &mut Span) { return; }; + if span_op.starts_with("cache.") { + if let Some(data) = span.data.value() { + if let Some(value) = match &data.cache_item_size.value() { + Some(Value::F64(f)) => Some(*f), + Some(Value::I64(i)) => Some(*i as f64), + Some(Value::U64(u)) => Some(*u as f64), + _ => None, + } { + let measurements = span.measurements.get_or_insert_with(Default::default); + measurements.insert( + "cache.item_size".to_owned(), + Measurement { + value: value.into(), + unit: MetricUnit::Information(InformationUnit::Byte).into(), + } + .into(), + ); + } + } + } + if span_op.starts_with("resource.") { if let Some(data) = span.data.value() { for (field, key) in [ @@ -1283,6 +1315,81 @@ LIMIT 1 assert!(!tags_3.contains_key("raw_domain")); } + #[test] + fn test_cache_extraction() { + let json = r#" + { + "spans": [ + { + "timestamp": 1694732408.3145, + "start_timestamp": 1694732407.8367, + "exclusive_time": 477.800131, + "description": "get my_key", + "op": "cache.get_item", + "span_id": "97c0ef9770a02f9d", + "parent_span_id": "9756d8d7b2b364ff", + "trace_id": "77aeb1c16bb544a4a39b8d42944947a3", + "data": { + "cache.hit": true, + "cache.item_size": 8, + "thread.id": "6286962688", + "thread.name": "Thread-4 (process_request_thread)" + + }, + "hash": "e2fae740cccd3781" + }, + { + "timestamp": 1694732409.3145, + "start_timestamp": 1694732408.8367, + "exclusive_time": 477.800131, + "description": "get my_key", + "op": "cache.get_item", + "span_id": "97c0ef9770a02f9d", + "parent_span_id": "9756d8d7b2b364ff", + "trace_id": "77aeb1c16bb544a4a39b8d42944947a3", + "data": { + "cache.hit": false, + "cache.item_size": 8, + "thread.id": "6286962688", + "thread.name": "Thread-4 (process_request_thread)" + + }, + "hash": "e2fae740cccd3781" + } + ] + } + "#; + + let mut event = Annotated::::from_json(json) + .unwrap() + .into_value() + .unwrap(); + + extract_span_tags_from_event(&mut event, 200); + + let span_1 = &event.spans.value().unwrap()[0]; + let span_2 = &event.spans.value().unwrap()[1]; + + let tags_1 = get_value!(span_1.sentry_tags).unwrap(); + let tags_2 = get_value!(span_2.sentry_tags).unwrap(); + let measurements_1 = span_1.value().unwrap().measurements.value().unwrap(); + + assert_eq!(tags_1.get("cache.hit").unwrap().as_str(), Some("true")); + assert_eq!(tags_2.get("cache.hit").unwrap().as_str(), Some("false")); + assert_debug_snapshot!(measurements_1, @r###" + Measurements( + { + "cache.item_size": Measurement { + value: 8.0, + unit: Information( + Byte, + ), + }, + }, + ) + "###); + } + #[test] fn test_mobile_specific_tags() { let json = r#" diff --git a/relay-event-schema/src/protocol/span.rs b/relay-event-schema/src/protocol/span.rs index 8f5a80f106..09bae7c485 100644 --- a/relay-event-schema/src/protocol/span.rs +++ b/relay-event-schema/src/protocol/span.rs @@ -231,10 +231,18 @@ pub struct SpanData { #[metastructure(field = "resource.render_blocking_status")] pub resource_render_blocking_status: Annotated, - /// Name of the database host. + /// Name of the web server host. #[metastructure(field = "server.address")] pub server_address: Annotated, + /// Whether cache was hit or miss on a read operation. + #[metastructure(field = "cache.hit")] + pub cache_hit: Annotated, + + /// The size of the cache item. + #[metastructure(field = "cache.item_size")] + pub cache_item_size: Annotated, + /// The status HTTP response. #[metastructure(field = "http.response.status_code", legacy_alias = "status_code")] pub http_response_status_code: Annotated, @@ -512,6 +520,8 @@ mod tests { http_response_transfer_size: ~, resource_render_blocking_status: ~, server_address: ~, + cache_hit: ~, + cache_item_size: ~, http_response_status_code: ~, ai_input_messages: ~, ai_completion_tokens_used: ~, 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 01d216f029..830d3a1512 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 @@ -324,6 +324,8 @@ expression: "(&event.value().unwrap().spans, metrics)" http_response_transfer_size: ~, resource_render_blocking_status: ~, server_address: ~, + cache_hit: ~, + cache_item_size: ~, http_response_status_code: ~, ai_input_messages: ~, ai_completion_tokens_used: ~, @@ -403,6 +405,8 @@ expression: "(&event.value().unwrap().spans, metrics)" http_response_transfer_size: ~, resource_render_blocking_status: ~, server_address: ~, + cache_hit: ~, + cache_item_size: ~, http_response_status_code: ~, ai_input_messages: ~, ai_completion_tokens_used: ~,