From f94030fdda7228a9a0f67b012dc6563dd772e4d3 Mon Sep 17 00:00:00 2001 From: David Herberth Date: Tue, 5 May 2026 16:09:36 +0200 Subject: [PATCH 1/2] ref(unreal): Stop double parsing the unreal context --- .../src/processing/errors/errors/unreal.rs | 2 +- relay-server/src/utils/unreal.rs | 61 +++++++++---------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/relay-server/src/processing/errors/errors/unreal.rs b/relay-server/src/processing/errors/errors/unreal.rs index 669abef1002..36ddd758daf 100644 --- a/relay-server/src/processing/errors/errors/unreal.rs +++ b/relay-server/src/processing/errors/errors/unreal.rs @@ -86,7 +86,7 @@ impl SentryError for Unreal { // // This is currently still split to avoid too many changes and code duplication at once. if let Some(result) = - crate::utils::process_unreal(event_id, &mut event, &attachments, user_header) + crate::utils::process_unreal(expansion.context, event_id, &mut event, &attachments, user_header) .map_err(ProcessingError::InvalidUnrealReport)? { user_reports.extend(result.user_reports); diff --git a/relay-server/src/utils/unreal.rs b/relay-server/src/utils/unreal.rs index c17217c5428..dda0a9af09e 100644 --- a/relay-server/src/utils/unreal.rs +++ b/relay-server/src/utils/unreal.rs @@ -23,22 +23,6 @@ const MAX_NUM_UNREAL_LOGS: usize = 40; /// Client SDK name used for the event payload to identify the UE4 crash reporter. const CLIENT_SDK_NAME: &str = "unreal.crashreporter"; -fn get_event_item(data: &[u8]) -> Result, Unreal4Error> { - let mut context = Unreal4Context::parse(data)?; - let json = match context - .game_data - .remove(crate::constants::SENTRY_CRASH_PAYLOAD_KEY) - { - Some(json) if !json.is_empty() => json, - _ => return Ok(None), - }; - - relay_log::trace!("adding event payload from unreal context"); - let mut item = Item::new(ItemType::Event); - item.set_payload(ContentType::Json, json); - Ok(Some(item)) -} - /// Extracts the items from an Unreal 4 crash report payload. pub fn extract_items(payload: Bytes, config: &Config) -> Result { let mut items = Items::new(); @@ -63,9 +47,6 @@ pub fn extract_items(payload: Bytes, config: &Config) -> Result. item.set_payload(content_type, file.into_bytes()); item.set_attachment_type(attachment_type); items.push(item); @@ -76,15 +57,17 @@ pub fn extract_items(payload: Bytes, config: &Config) -> Result Result { - let event = items + let mut context = items .iter() .find(|&item| matches!(item.attachment_type(), Some(AttachmentType::UnrealContext))) - .map(|item| get_event_item(&item.payload())) - .transpose()? - .flatten(); + .map(|item| Unreal4Context::parse(&item.payload())) + .transpose()?; + + let event = context.as_mut().and_then(take_event_item); Ok(UnrealExpansion { event, + context, attachments: items, }) } @@ -101,11 +84,31 @@ pub struct UnrealExpansion { /// The error event if the crash contained one. #[cfg_attr(not(feature = "processing"), expect(unused))] pub event: Option, + /// The parsed unreal context. + /// + /// Note: the raw unreal context may still be in [`Self::attachments`]. + #[cfg_attr(not(feature = "processing"), expect(unused))] + pub context: Option, /// Files of the report as attachments. #[cfg_attr(not(feature = "processing"), expect(unused))] pub attachments: Items, } +fn take_event_item(context: &mut Unreal4Context) -> Option { + let json = context + .game_data + .remove(crate::constants::SENTRY_CRASH_PAYLOAD_KEY)?; + + if json.is_empty() { + return None; + } + + relay_log::trace!("adding event payload from unreal context"); + let mut item = Item::new(ItemType::Event); + item.set_payload(ContentType::Json, json); + Some(item) +} + fn merge_unreal_user_info(event: &mut Event, user_info: &str) { let mut parts = user_info.split('|'); @@ -351,16 +354,12 @@ fn merge_unreal_context(event: &mut Event, context: Unreal4Context) { /// The `user_header` should be extracted from the [`crate::constants::UNREAL_USER_HEADER`] envelope header. #[cfg_attr(not(feature = "processing"), expect(unused))] pub fn process_unreal<'a>( + context: Option, event_id: EventId, event: &mut Annotated, attachments: impl IntoIterator + Clone, user_header: Option<&str>, ) -> Result, Unreal4Error> { - let context_item = attachments - .clone() - .into_iter() - .find(|item| item.attachment_type() == Some(AttachmentType::UnrealContext)); - let mut logs_items = attachments .into_iter() .filter(|item| item.attachment_type() == Some(AttachmentType::UnrealLogs)) @@ -368,7 +367,7 @@ pub fn process_unreal<'a>( .peekable(); // Early exit if there is no information. - if user_header.is_none() && context_item.is_none() && logs_items.peek().is_none() { + if context.is_none() && user_header.is_none() && logs_items.peek().is_none() { return Ok(None); } @@ -383,9 +382,7 @@ pub fn process_unreal<'a>( merge_unreal_logs(event, logs_items)?; let mut user_reports = Items::new(); - if let Some(context_item) = context_item { - let mut context = Unreal4Context::parse(&context_item.payload())?; - + if let Some(mut context) = context { if let Some(report) = get_unreal_user_report(event_id, &mut context) { user_reports.push(report); } From bfd063884c7e25ccd4e17699cf7f8e868d6654ef Mon Sep 17 00:00:00 2001 From: David Herberth Date: Tue, 5 May 2026 16:30:11 +0200 Subject: [PATCH 2/2] bugbot found one --- relay-server/src/utils/unreal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relay-server/src/utils/unreal.rs b/relay-server/src/utils/unreal.rs index dda0a9af09e..7bd870b5f1e 100644 --- a/relay-server/src/utils/unreal.rs +++ b/relay-server/src/utils/unreal.rs @@ -357,7 +357,7 @@ pub fn process_unreal<'a>( context: Option, event_id: EventId, event: &mut Annotated, - attachments: impl IntoIterator + Clone, + attachments: impl IntoIterator, user_header: Option<&str>, ) -> Result, Unreal4Error> { let mut logs_items = attachments