From 2f720e9b7f947c1fe326df510c78f41f7bfb7a7c Mon Sep 17 00:00:00 2001 From: David Herberth Date: Wed, 20 May 2026 13:19:40 +0200 Subject: [PATCH 1/3] ref(errors): Unconditionally create a trace context --- CHANGELOG.md | 4 + relay-cabi/src/processing.rs | 2 +- relay-dynamic-config/src/feature.rs | 3 - relay-event-normalization/src/event.rs | 158 +++++------------- .../src/normalize/contexts.rs | 4 + .../src/protocol/contexts/trace.rs | 54 +----- relay-server/src/processing/utils/event.rs | 2 +- tests/fixtures/extended-event-output.json | 8 +- tests/integration/test_flags.py | 21 +-- tests/integration/test_minidump.py | 8 + tests/integration/test_normalization.py | 54 ++++++ 11 files changed, 143 insertions(+), 175 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 690183ec364..74b89e5047d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ - Obtain PII values for `SpanData` fields from `sentry-conventions`. ([#5997](https://github.com/getsentry/relay/pull/5997)) - Add `sentry.dsc.transaction` and `sentry.dsc.trace_id` to all standalone spans. ([#6001](https://github.com/getsentry/relay/pull/6001), [#6004](https://github.com/getsentry/relay/pull/6004)) +**Internal**: + +- Unconditionally create a trace context with a trace id for errors. ([#6009](https://github.com/getsentry/relay/pull/6009)) + ## 26.5.0 **Features**: diff --git a/relay-cabi/src/processing.rs b/relay-cabi/src/processing.rs index 94bdb65f6ce..c9325b5afdb 100644 --- a/relay-cabi/src/processing.rs +++ b/relay-cabi/src/processing.rs @@ -274,7 +274,7 @@ pub unsafe extern "C" fn relay_store_normalizer_normalize_event( span_allowed_hosts: &[], // only supported in relay span_op_defaults: Default::default(), // only supported in relay performance_issues_spans: Default::default(), - derive_trace_id: Default::default(), + force_trace_context: true, // always required for Sentry }; normalize_event(&mut event, &normalization_config); diff --git a/relay-dynamic-config/src/feature.rs b/relay-dynamic-config/src/feature.rs index 6febf8f625e..15b86392c6e 100644 --- a/relay-dynamic-config/src/feature.rs +++ b/relay-dynamic-config/src/feature.rs @@ -95,9 +95,6 @@ pub enum Feature { /// Upload non-prosperodmp playstation attachments via the upload endpoint. #[serde(rename = "projects:relay-playstation-uploads")] PlaystationUploads, - /// Add a random trace ID to events that lack one. - #[serde(rename = "organizations:relay-default-trace-id")] - AddDefaultTraceID, /// Enable experimental expansion of the unreal report in the endpoint rather than in the /// processor. Only enable for organizations with sufficient attachment quota. #[serde(rename = "organizations:relay-unreal-endpoint-expansion")] diff --git a/relay-event-normalization/src/event.rs b/relay-event-normalization/src/event.rs index ca1d4a67a95..cc1b64c125c 100644 --- a/relay-event-normalization/src/event.rs +++ b/relay-event-normalization/src/event.rs @@ -24,10 +24,10 @@ use relay_conventions::measurements::{ }; use relay_event_schema::processor::{self, ProcessingAction, ProcessingState, Processor}; use relay_event_schema::protocol::{ - AsPair, Attributes, AutoInferSetting, ClientSdkInfo, Context, ContextInner, Contexts, - DebugImage, DeviceClass, Event, EventId, EventType, Exception, Headers, IpAddr, Level, - LogEntry, Measurement, Measurements, PerformanceScoreContext, ReplayContext, Request, Span, - SpanStatus, SpanV2, Tags, Timestamp, TraceContext, User, VALID_PLATFORMS, + AsPair, Attributes, AutoInferSetting, ClientSdkInfo, Contexts, DebugImage, DeviceClass, Event, + EventId, EventType, Exception, Headers, IpAddr, Level, LogEntry, Measurement, Measurements, + PerformanceScoreContext, ReplayContext, Request, Span, SpanId, SpanV2, Tags, Timestamp, + TraceContext, TraceId, User, VALID_PLATFORMS, }; use relay_protocol::{ Annotated, Empty, Error, ErrorKind, FiniteF64, FromValue, Getter, Meta, Object, Remark, @@ -173,8 +173,17 @@ pub struct NormalizationConfig<'a> { /// Set a flag to enable performance issue detection on spans. pub performance_issues_spans: bool, - /// Should add a random trace ID to events that lack one. - pub derive_trace_id: bool, + /// Forces a valid trace context for error events. + /// + /// Sentry requires a valid trace context for events. This ensures a valid trace context always + /// exists. + /// + /// If the error does not contain a trace context, one will be created. If there is already an + /// existing trace context, it ensures it's valid and has a trace id. + /// + /// This is never applied to transaction events, which require a valid transaction context from + /// the SDK. + pub force_trace_context: bool, } impl Default for NormalizationConfig<'_> { @@ -209,7 +218,7 @@ impl Default for NormalizationConfig<'_> { span_allowed_hosts: Default::default(), span_op_defaults: Default::default(), performance_issues_spans: Default::default(), - derive_trace_id: Default::default(), + force_trace_context: Default::default(), } } } @@ -334,11 +343,12 @@ fn normalize(event: &mut Event, meta: &mut Meta, config: &NormalizationConfig) { Ok(()) }); - // We know this exists thanks to normalize_default_attributes. - let event_id = event.id.value().unwrap().0; + if config.force_trace_context && event.ty.value() != Some(&EventType::Transaction) { + normalize_force_trace_context(event); + } // Some contexts need to be normalized before metrics extraction takes place. - normalize_contexts(&mut event.contexts, event_id, config); + normalize_contexts(&mut event.contexts); if config.normalize_spans && event.ty.value() == Some(&EventType::Transaction) { crate::normalize::normalize_app_start_spans(event); @@ -1358,34 +1368,34 @@ fn remove_logger_word(tokens: &mut Vec<&str>) { } } -/// Normalizes incoming contexts for the downstream metric extraction. -fn normalize_contexts( - contexts: &mut Annotated, - event_id: Uuid, - config: &NormalizationConfig, -) { - if config.derive_trace_id { - // We will always need a TraceContext. - let _ = contexts.get_or_insert_with(Contexts::new); - } +/// Creates a new trace context if it is missing and ensures the context has a valid trace and span id. +/// +/// The function keeps existing meta on trace and span id intact, still surfacing user errors in the +/// original payload. +fn normalize_force_trace_context(event: &mut Event) { + let contexts = event.contexts.get_or_insert_with(Contexts::new); + let trace = contexts.get_or_default::(); + + let trace_id = trace + .trace_id + .get_or_insert_with(|| TraceId::from(*event.id.get_or_insert_with(Default::default))); + let _ = trace.span_id.get_or_insert_with(|| { + // Derive the span id from the trace id, for a stable id. + // This is equally as good as creating an invented random id. + let [a, b, c, d, e, f, g, h, ..] = *trace_id.as_bytes(); + SpanId([a, b, c, d, e, f, g, h]) + }); +} +/// Normalizes incoming contexts for the downstream metric extraction. +fn normalize_contexts(contexts: &mut Annotated) { let _ = processor::apply(contexts, |contexts, _meta| { // Reprocessing context sent from SDKs must not be accepted, it is a Sentry-internal // construct. // [`normalize`] does not run on renormalization anyway. contexts.0.remove("reprocessing"); - // We need a TraceId to ingest the event into EAP. - // If the event lacks a TraceContext, add a random one. - - if config.derive_trace_id && !contexts.contains::() { - contexts.add(TraceContext::random(event_id)) - } - for annotated in &mut contexts.0.values_mut() { - if let Some(ContextInner(Context::Trace(context))) = annotated.value_mut() { - context.status.get_or_insert_with(|| SpanStatus::Unknown); - } if let Some(context_inner) = annotated.value_mut() { crate::normalize::contexts::normalize_context(&mut context_inner.0); } @@ -4925,48 +4935,23 @@ mod tests { } #[test] - fn test_normalize_adds_trace_id() { + fn test_normalize_adds_trace_context() { let json = r#" { - "type": "transaction", - "timestamp": "2021-04-26T08:00:05+0100", - "start_timestamp": "2021-04-26T08:00:00+0100", - "measurements": { - "inp": {"value": 120.0} + "type": "error", + "exception": { + "values": [{"type": "ValueError", "value": "Should not happen"}] } } "#; let mut event = Annotated::::from_json(json).unwrap().0.unwrap(); - let performance_score: PerformanceScoreConfig = serde_json::from_value(json!({ - "profiles": [ - { - "name": "Desktop", - "scoreComponents": [ - { - "measurement": "inp", - "weight": 1.0, - "p10": 0.1, - "p50": 0.25 - }, - ], - "condition": { - "op":"and", - "inner": [] - }, - "version": "beta" - } - ] - })) - .unwrap(); - normalize( &mut event, &mut Meta::default(), &NormalizationConfig { - performance_score: Some(&performance_score), - derive_trace_id: true, + force_trace_context: true, ..Default::default() }, ); @@ -4977,67 +4962,14 @@ mod tests { ".trace.span_id" => "[span-id]" }, @r#" { - "performance_score": { - "score_profile_version": "beta", - "type": "performancescore", - }, "trace": { "trace_id": "[trace-id]", "span_id": "[span-id]", "status": "unknown", - "exclusive_time": 5000.0, "type": "trace", }, - "_meta": { - "trace": { - "span_id": { - "": Meta(Some(MetaInner( - rem: [ - [ - "span_id.missing", - s, - ], - ], - ))), - }, - "trace_id": { - "": Meta(Some(MetaInner( - rem: [ - [ - "trace_id.missing", - s, - ], - ], - ))), - }, - }, - }, } "#); - insta::assert_ron_snapshot!(SerializableAnnotated(&event.measurements), {}, @r###" - { - "inp": { - "value": 120.0, - "unit": "millisecond", - }, - "score.inp": { - "value": 0.0, - "unit": "ratio", - }, - "score.ratio.inp": { - "value": 0.0, - "unit": "ratio", - }, - "score.total": { - "value": 0.0, - "unit": "ratio", - }, - "score.weight.inp": { - "value": 1.0, - "unit": "ratio", - }, - } - "###); } #[test] diff --git a/relay-event-normalization/src/normalize/contexts.rs b/relay-event-normalization/src/normalize/contexts.rs index cf6f109d72c..5765af4ab02 100644 --- a/relay-event-normalization/src/normalize/contexts.rs +++ b/relay-event-normalization/src/normalize/contexts.rs @@ -4,6 +4,7 @@ use std::collections::HashMap; use std::sync::LazyLock; use regex::Regex; +use relay_base_schema::spans::SpanStatus; use relay_event_schema::protocol::{ BrowserContext, Context, Cookies, OsContext, ResponseContext, RuntimeContext, }; @@ -382,6 +383,9 @@ pub fn normalize_context(context: &mut Context) { device.name.set_value(Some(product_name.to_string())) } } + Context::Trace(trace) => { + trace.status.get_or_insert_with(|| SpanStatus::Unknown); + } _ => {} } } diff --git a/relay-event-schema/src/protocol/contexts/trace.rs b/relay-event-schema/src/protocol/contexts/trace.rs index 663605b8448..dad5326c33b 100644 --- a/relay-event-schema/src/protocol/contexts/trace.rs +++ b/relay-event-schema/src/protocol/contexts/trace.rs @@ -9,7 +9,7 @@ use std::str::FromStr; use uuid::Uuid; use crate::processor::ProcessValue; -use crate::protocol::{OperationType, OriginType, SpanData, SpanLink, SpanStatus}; +use crate::protocol::{EventId, OperationType, OriginType, SpanData, SpanLink, SpanStatus}; /// Represents a W3C Trace Context `trace-id`. /// @@ -112,6 +112,12 @@ impl From for TraceId { } } +impl From for TraceId { + fn from(event_id: EventId) -> Self { + Self::from(event_id.0) + } +} + impl From for Uuid { fn from(trace_id: TraceId) -> Self { trace_id.0 @@ -170,7 +176,7 @@ impl IntoValue for TraceId { /// A 16-character hex string as described in the W3C trace context spec, stored /// internally as an array of 8 bytes. #[derive(Clone, Copy, Default, Eq, Hash, PartialEq, Ord, PartialOrd)] -pub struct SpanId([u8; 8]); +pub struct SpanId(pub [u8; 8]); relay_common::impl_str_serde!(SpanId, "a span identifier"); @@ -337,23 +343,6 @@ pub struct TraceContext { pub other: Object, } -impl TraceContext { - /// Generates a random [`SpanId`] and takes `[TraceId]` from the event's UUID. - /// Leaves all other fields blank. - pub fn random(event_id: Uuid) -> Self { - let mut trace_meta = Meta::default(); - trace_meta.add_remark(Remark::new(RemarkType::Substituted, "trace_id.missing")); - - let mut span_meta = Meta::default(); - span_meta.add_remark(Remark::new(RemarkType::Substituted, "span_id.missing")); - TraceContext { - trace_id: Annotated(Some(TraceId::from(event_id)), trace_meta), - span_id: Annotated(Some(SpanId::random()), span_meta), - ..Default::default() - } - } -} - impl super::DefaultContext for TraceContext { fn default_key() -> &'static str { "trace" @@ -645,31 +634,4 @@ mod tests { let remark = annotated.meta().iter_remarks().next().unwrap(); assert_eq!(remark.rule_id(), "trace_id.invalid"); } - - #[test] - fn test_random_trace_context() { - let rand_context = TraceContext::random(Uuid::new_v4()); - assert!(rand_context.trace_id.value().is_some()); - assert_eq!( - rand_context - .trace_id - .meta() - .iter_remarks() - .next() - .unwrap() - .rule_id(), - "trace_id.missing" - ); - assert!(rand_context.span_id.value().is_some()); - assert_eq!( - rand_context - .span_id - .meta() - .iter_remarks() - .next() - .unwrap() - .rule_id(), - "span_id.missing" - ); - } } diff --git a/relay-server/src/processing/utils/event.rs b/relay-server/src/processing/utils/event.rs index 7c2e63a0ab1..2cacd05d0c5 100644 --- a/relay-server/src/processing/utils/event.rs +++ b/relay-server/src/processing/utils/event.rs @@ -301,7 +301,7 @@ pub fn normalize( performance_issues_spans: ctx .project_info .has_feature(Feature::PerformanceIssuesSpans), - derive_trace_id: project_info.has_feature(Feature::AddDefaultTraceID), + force_trace_context: true, }; metric!(timer(RelayTimers::EventProcessingNormalization), { diff --git a/tests/fixtures/extended-event-output.json b/tests/fixtures/extended-event-output.json index 818a02f9c68..f39ab00d91b 100644 --- a/tests/fixtures/extended-event-output.json +++ b/tests/fixtures/extended-event-output.json @@ -80,7 +80,13 @@ "name": "Python Requests", "version": "2.26", "type": "browser" - } + }, + "trace": { + "span_id": "69241adef5744ef1", + "status": "unknown", + "trace_id": "69241adef5744ef19bde5bbd06fe8177", + "type": "trace" + } }, "exception": { "values": [ diff --git a/tests/integration/test_flags.py b/tests/integration/test_flags.py index 9f09ab51521..9ae138eebdb 100644 --- a/tests/integration/test_flags.py +++ b/tests/integration/test_flags.py @@ -32,12 +32,10 @@ def test_event_with_flags(relay, mini_sentry): envelope = mini_sentry.get_captured_envelope() assert envelope - assert envelope.items[0].payload.json["contexts"] == { - "flags": { - "values": [{"flag": "hello", "result": "world", "key": "value"}], - "abc": "def", - "type": "flags", - } + assert envelope.items[0].payload.json["contexts"]["flags"] == { + "values": [{"flag": "hello", "result": "world", "key": "value"}], + "abc": "def", + "type": "flags", } assert mini_sentry.captured_envelopes.empty() @@ -65,8 +63,10 @@ def test_event_with_flags_malformed(relay, mini_sentry): # Malformed fields are removed. Unknown fields are passed through. envelope = mini_sentry.get_captured_envelope() assert envelope - assert envelope.items[0].payload.json["contexts"] == { - "flags": {"values": None, "key": "value", "type": "flags"} + assert envelope.items[0].payload.json["contexts"]["flags"] == { + "values": None, + "key": "value", + "type": "flags", } assert mini_sentry.captured_envelopes.empty() @@ -100,7 +100,8 @@ def test_event_with_flags_malformed_inner_object(relay, mini_sentry): # Malformed fields are removed. Unknown fields are passed through. envelope = mini_sentry.get_captured_envelope() assert envelope - assert envelope.items[0].payload.json["contexts"] == { - "flags": {"values": [{"flag": None, "key": "key"}, None], "type": "flags"} + assert envelope.items[0].payload.json["contexts"]["flags"] == { + "values": [{"flag": None, "key": "key"}, None], + "type": "flags", } assert mini_sentry.captured_envelopes.empty() diff --git a/tests/integration/test_minidump.py b/tests/integration/test_minidump.py index 686bd4290bb..72d4b5d70ae 100644 --- a/tests/integration/test_minidump.py +++ b/tests/integration/test_minidump.py @@ -856,6 +856,14 @@ def test_minidump_placeholder( }, ], }, + "contexts": { + "trace": { + "span_id": "515539018c9b4260", + "status": "unknown", + "trace_id": "515539018c9b4260a6f999572f1661ee", + "type": "trace", + }, + }, "grouping_config": mock.ANY, "key_id": "123", "level": "fatal", diff --git a/tests/integration/test_normalization.py b/tests/integration/test_normalization.py index 81361dfd093..b8f092c2c3c 100644 --- a/tests/integration/test_normalization.py +++ b/tests/integration/test_normalization.py @@ -696,3 +696,57 @@ def test_auto_infer_invalid_setting(mini_sentry, relay): envelope = mini_sentry.get_captured_envelope() event = envelope.get_event() assert event.get("user", {}).get("ip_address", None) is None + + +def test_create_trace_context_for_errors(mini_sentry, relay): + """ + Makes sure events always have a default trace context created, if it is missing. + """ + project_id = 42 + relay = relay(mini_sentry) + mini_sentry.add_basic_project_config(project_id) + + relay.send_event( + project_id, + {"event_id": "69241adef5744ef19bde5bbd06fe8177", "message": "Hello World!"}, + ) + + event = mini_sentry.get_captured_envelope().get_event() + assert event.get("contexts", {}).get("trace") == { + "trace_id": "69241adef5744ef19bde5bbd06fe8177", + "span_id": "69241adef5744ef1", + "status": "unknown", + "type": "trace", + } + + +def test_create_trace_context_for_errors_with_partial_context(mini_sentry, relay): + """ + Makes sure events always have a valid trace context, even if the one contained in the event + is missing required attributes like the trace id. + """ + project_id = 42 + relay = relay(mini_sentry) + mini_sentry.add_basic_project_config(project_id) + + relay.send_event( + project_id, + { + "event_id": "69241adef5744ef19bde5bbd06fe8177", + "message": "Hello World!", + "contexts": { + "trace": { + "span_id": "1233333333333333", + "type": "trace", + } + }, + }, + ) + + event = mini_sentry.get_captured_envelope().get_event() + assert event.get("contexts", {}).get("trace") == { + "trace_id": "69241adef5744ef19bde5bbd06fe8177", + "span_id": "1233333333333333", + "status": "unknown", + "type": "trace", + } From 8a4c17b8180d549b481d6b2e1080976b72f3210e Mon Sep 17 00:00:00 2001 From: David Herberth Date: Wed, 20 May 2026 14:10:12 +0200 Subject: [PATCH 2/3] properly derive span id --- relay-event-normalization/src/event.rs | 9 +++---- .../src/protocol/contexts/trace.rs | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/relay-event-normalization/src/event.rs b/relay-event-normalization/src/event.rs index cc1b64c125c..8a16a00d5c5 100644 --- a/relay-event-normalization/src/event.rs +++ b/relay-event-normalization/src/event.rs @@ -1379,12 +1379,9 @@ fn normalize_force_trace_context(event: &mut Event) { let trace_id = trace .trace_id .get_or_insert_with(|| TraceId::from(*event.id.get_or_insert_with(Default::default))); - let _ = trace.span_id.get_or_insert_with(|| { - // Derive the span id from the trace id, for a stable id. - // This is equally as good as creating an invented random id. - let [a, b, c, d, e, f, g, h, ..] = *trace_id.as_bytes(); - SpanId([a, b, c, d, e, f, g, h]) - }); + let _ = trace + .span_id + .get_or_insert_with(|| SpanId::derive_from_trace_id(trace_id)); } /// Normalizes incoming contexts for the downstream metric extraction. diff --git a/relay-event-schema/src/protocol/contexts/trace.rs b/relay-event-schema/src/protocol/contexts/trace.rs index dad5326c33b..afb3244f1b4 100644 --- a/relay-event-schema/src/protocol/contexts/trace.rs +++ b/relay-event-schema/src/protocol/contexts/trace.rs @@ -185,6 +185,31 @@ impl SpanId { let value: u64 = rand::random_range(1..=u64::MAX); Self(value.to_ne_bytes()) } + + /// Derives a [`SpanId`] deterministically from a [`TraceId`]. + /// + /// ``` + /// # use relay_event_schema::protocol::{SpanId, TraceId}; + /// # + /// let trace_id: TraceId = "515539018c9b4260a6f999572f1661ee".parse().unwrap(); + /// let span_id = SpanId::derive_from_trace_id(&trace_id); + /// assert_eq!(span_id, "515539018c9b4260".parse().unwrap()); + /// + /// let trace_id: TraceId = "00000000000000000000000000000001".parse().unwrap(); + /// let span_id = SpanId::derive_from_trace_id(&trace_id); + /// assert_eq!(span_id, "0000000000000001".parse().unwrap()); + /// ``` + pub fn derive_from_trace_id(trace_id: &TraceId) -> Self { + let [first @ .., a, b, c, d, e, f, g, h]: [u8; 16] = *trace_id.as_bytes(); + let second = [a, b, c, d, e, f, g, h]; + + // A trace id may never be nil, this means either the first or the second half needs to + // contain at least one non-zero value, making the resulting span id valid. + match first { + [0, 0, 0, 0, 0, 0, 0, 0] => SpanId(second), + _ => SpanId(first), + } + } } impl FromStr for SpanId { From ac2fafcb63ae844dedb6e0f00fd667815fce09f3 Mon Sep 17 00:00:00 2001 From: David Herberth Date: Wed, 20 May 2026 14:21:16 +0200 Subject: [PATCH 3/3] some more test fixes --- py/tests/test_processing.py | 4 +++- tests/integration/test_playstation.py | 4 ++++ tests/integration/test_security_report.py | 8 ++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/py/tests/test_processing.py b/py/tests/test_processing.py index 256fcb7f915..d7e241d62fd 100644 --- a/py/tests/test_processing.py +++ b/py/tests/test_processing.py @@ -1,3 +1,4 @@ +from unittest import mock import sentry_relay import pytest @@ -127,9 +128,10 @@ def test_normalize_user_agent(must_normalize): "type": "browser", }, "client_os": {"name": "Ubuntu", "os": "Ubuntu", "type": "os"}, + "trace": mock.ANY, } else: - assert "contexts" not in event + assert set(event["contexts"].keys()) == {"trace"} def test_validate_pii_selector(): diff --git a/tests/integration/test_playstation.py b/tests/integration/test_playstation.py index 771f0e7bb79..9f6940a7503 100644 --- a/tests/integration/test_playstation.py +++ b/tests/integration/test_playstation.py @@ -147,6 +147,7 @@ def playstation_event_json(sdk=mock.ANY): "version": "9.20.00.05-00.00.00.0.1", "type": "runtime", }, + "trace": mock.ANY, }, "exception": { "values": [ @@ -783,6 +784,9 @@ def test_playstation_attachment_no_feature_flag( "sdk": {"name": "raven-node", "version": "2.6.3"}, "key_id": "123", "project": 42, + "contexts": { + "trace": mock.ANY, + }, "grouping_config": { "enhancements": "eJybzDhxY05qemJypZWRgaGlroGxrqHRBABbEwcC", "id": "legacy:2019-03-12", diff --git a/tests/integration/test_security_report.py b/tests/integration/test_security_report.py index 56dab5ad79e..8b9ead2c5a7 100644 --- a/tests/integration/test_security_report.py +++ b/tests/integration/test_security_report.py @@ -95,6 +95,7 @@ def test_security_report_with_processing( expected_evt = fixture_provider.load(test_name, ext) event.pop("_metrics", None) + event.get("contexts", {}).pop("trace", None) assert event == expected_evt @@ -277,10 +278,9 @@ def test_security_report(mini_sentry, relay, test_case, json_fixture_provider): ext = ".no_processing.output" expected_evt = fixture_provider.load(test_name, ext) - if "received" in event: - event.pop("received") - if "timestamp" in event: - event.pop("timestamp") + event.pop("received", None) + event.pop("timestamp", None) + event.get("contexts", {}).pop("trace", None) assert event == expected_evt