From 90fca0b08869f1427da953b00deb4375e0f2c87a Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Wed, 9 Jul 2025 17:07:58 -0400 Subject: [PATCH 1/9] Add test case for array attributes --- relay-spans/src/otel_to_sentry.rs | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/relay-spans/src/otel_to_sentry.rs b/relay-spans/src/otel_to_sentry.rs index e3acb54a8f6..5f5de2c25b8 100644 --- a/relay-spans/src/otel_to_sentry.rs +++ b/relay-spans/src/otel_to_sentry.rs @@ -393,6 +393,56 @@ mod tests { "###); } + #[test] + fn parse_array_attribute() { + let json = r#"{ + "traceId": "4c79f60c11214eb38604f4ae0781bfb2", + "spanId": "fa90fdead5f74052", + "parentSpanId": "fa90fdead5f74051", + "startTimeUnixNano": "123000000000", + "endTimeUnixNano": "123500000000", + "name": "cmd.run", + "status": {"code": 0}, + "attributes": [ + { + "key": "process.args", + "value": { + "arrayValue": { + "values": [ + {"stringValue": "node"}, + {"stringValue": "--require"}, + {"stringValue": "preflight.cjs"} + ] + } + } + } + ] + }"#; + + let otel_span: OtelSpan = serde_json::from_str(json).unwrap(); + let event_span = otel_to_sentry_span(otel_span).unwrap(); + + let annotated_span: Annotated = Annotated::new(event_span); + insta::assert_json_snapshot!(SerializableAnnotated(&annotated_span), @r###" + { + "timestamp": 123.5, + "start_timestamp": 123.0, + "exclusive_time": 500.0, + "op": "default", + "span_id": "fa90fdead5f74052", + "parent_span_id": "fa90fdead5f74051", + "trace_id": "4c79f60c11214eb38604f4ae0781bfb2", + "status": "ok", + "description": "cmd.run", + "data": { + "sentry.name": "cmd.run", + "sentry.status.message": "" + }, + "links": [] + } + "###); + } + /// Intended to be synced with `relay-event-schema::protocol::span::convert::tests::roundtrip`. #[test] fn parse_sentry_attributes() { From 3f5653ea4a957067d088cac937bbb077f1479c91 Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Thu, 10 Jul 2025 14:29:27 -0400 Subject: [PATCH 2/9] Add test for serialized JSON attribute --- relay-spans/src/otel_to_sentry.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/relay-spans/src/otel_to_sentry.rs b/relay-spans/src/otel_to_sentry.rs index 5f5de2c25b8..55d8ff825dc 100644 --- a/relay-spans/src/otel_to_sentry.rs +++ b/relay-spans/src/otel_to_sentry.rs @@ -437,6 +437,7 @@ mod tests { "data": { "sentry.name": "cmd.run", "sentry.status.message": "" + "process.args": "[\"node\",\"--require\",\"preflight.cjs\"]" }, "links": [] } From 1be25824c0f493a559aa7706f7caa884688bf6bb Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Thu, 10 Jul 2025 14:40:56 -0400 Subject: [PATCH 3/9] Serialize array attributes as strings --- relay-spans/src/otel_to_sentry.rs | 19 ++++++++++++- relay-spans/src/otel_to_sentry_v2.rs | 42 +++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/relay-spans/src/otel_to_sentry.rs b/relay-spans/src/otel_to_sentry.rs index 55d8ff825dc..f6c971ead20 100644 --- a/relay-spans/src/otel_to_sentry.rs +++ b/relay-spans/src/otel_to_sentry.rs @@ -415,6 +415,22 @@ mod tests { ] } } + }, + { + "key": "process.info", + "value": { + "arrayValue": { + "values": [ + {"intValue": 41}, + { + "arrayValue": { + "values": [ + {"intValue": 42} + ]} + } + ] + } + } } ] }"#; @@ -435,9 +451,10 @@ mod tests { "status": "ok", "description": "cmd.run", "data": { + "process.args": "[\"node\",\"--require\",\"preflight.cjs\"]" + "process.info": "[41]", "sentry.name": "cmd.run", "sentry.status.message": "" - "process.args": "[\"node\",\"--require\",\"preflight.cjs\"]" }, "links": [] } diff --git a/relay-spans/src/otel_to_sentry_v2.rs b/relay-spans/src/otel_to_sentry_v2.rs index e9effef38e6..0a44c65b7b8 100644 --- a/relay-spans/src/otel_to_sentry_v2.rs +++ b/relay-spans/src/otel_to_sentry_v2.rs @@ -146,7 +146,43 @@ fn otel_value_to_attr(otel_value: OtelValue) -> Option { let s = String::from_utf8(bytes).ok()?; (AttributeType::String, Value::String(s)) } - OtelValue::ArrayValue(_) | OtelValue::KvlistValue(_) => return None, + OtelValue::ArrayValue(array) => { + // Technically, `ArrayValue` can contain other arrays, or nested key-value lists. This + // is not usually allowed by the OTLP protocol, but for safety we filter those values + // out before serializing. + let safe_values: Vec = array + .values + .into_iter() + .filter_map(|v| v.value) + .filter_map(|v| match v { + OtelValue::StringValue(s) => Some(serde_json::Value::String(s)), + OtelValue::BoolValue(b) => Some(serde_json::Value::Bool(b)), + OtelValue::IntValue(i) => { + Some(serde_json::Value::Number(serde_json::Number::from(i))) + } + OtelValue::DoubleValue(d) => { + serde_json::Number::from_f64(d).map(serde_json::Value::Number) + } + OtelValue::BytesValue(bytes) => { + String::from_utf8(bytes).ok().map(serde_json::Value::String) + } + OtelValue::ArrayValue(_) | OtelValue::KvlistValue(_) => None, + }) + .collect(); + + // Serialize the arrays values as a JSON string. Even though there is some nominal + // support for array values in Sentry, it's not robust and not ready to be used. + // Instead, serialize arrays to a JSON string, and have the UI decode the JSON if + // possible. + let json = serde_json::to_string(&safe_values).unwrap_or_default(); + (AttributeType::String, Value::String(json)) + } + OtelValue::KvlistValue(_) => { + // Key-value pairs are supported by the type definition, but the OTLP protocol does + // _not_ allow setting this kind of value on a span, so we don't need to handle this + // case + return None; + } }; Some(Attribute::new(ty, value)) @@ -682,6 +718,10 @@ mod tests { "type": "string", "value": "prod" }, + "sentry.metrics_summary.some_metric": { + "type": "string", + "value": "[]" + }, "sentry.op": { "type": "string", "value": "myop" From 7945f7e0658b63624a6e880f7e483c06903d438e Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Thu, 10 Jul 2025 14:46:28 -0400 Subject: [PATCH 4/9] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e25b738c834..962f5d8c243 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ **Features**: - Add mechanism to allow ingestion only from trusted relays. ([#4772](https://github.com/getsentry/relay/pull/4772)) +- Serialize array attributes to JSON ([#4930](https://github.com/getsentry/relay/pull/4930)) **Bug Fixes**: From 501f38ba6089cbb04dbdc05bf98d5c5c38091df8 Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Thu, 10 Jul 2025 15:09:48 -0400 Subject: [PATCH 5/9] Update snapshots --- relay-spans/src/otel_to_sentry.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/relay-spans/src/otel_to_sentry.rs b/relay-spans/src/otel_to_sentry.rs index f6c971ead20..ce8f5d0ef9e 100644 --- a/relay-spans/src/otel_to_sentry.rs +++ b/relay-spans/src/otel_to_sentry.rs @@ -451,7 +451,7 @@ mod tests { "status": "ok", "description": "cmd.run", "data": { - "process.args": "[\"node\",\"--require\",\"preflight.cjs\"]" + "process.args": "[\"node\",\"--require\",\"preflight.cjs\"]", "process.info": "[41]", "sentry.name": "cmd.run", "sentry.status.message": "" @@ -613,6 +613,7 @@ mod tests { "sentry.release": "myapp@1.0.0", "sentry.segment.name": "my 1st transaction", "sentry.sdk.name": "sentry.php", + "sentry.metrics_summary.some_metric": "[]", "sentry.name": "myname", "sentry.status.message": "foo" }, From ab3773c468eb84c2a4ba8d03f890de2df2d88903 Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Fri, 11 Jul 2025 09:32:08 -0400 Subject: [PATCH 6/9] Update PR title --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 962f5d8c243..191f428c41c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Features**: - Add mechanism to allow ingestion only from trusted relays. ([#4772](https://github.com/getsentry/relay/pull/4772)) -- Serialize array attributes to JSON ([#4930](https://github.com/getsentry/relay/pull/4930)) +- Serialize standalone span array attributes to JSON ([#4930](https://github.com/getsentry/relay/pull/4930)) **Bug Fixes**: From 2eec109734e4731d555656eb749c9f7086a4d8bb Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Fri, 11 Jul 2025 09:33:07 -0400 Subject: [PATCH 7/9] Collapse filter map calls --- relay-spans/src/otel_to_sentry_v2.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/relay-spans/src/otel_to_sentry_v2.rs b/relay-spans/src/otel_to_sentry_v2.rs index 0a44c65b7b8..d8fade73589 100644 --- a/relay-spans/src/otel_to_sentry_v2.rs +++ b/relay-spans/src/otel_to_sentry_v2.rs @@ -153,8 +153,7 @@ fn otel_value_to_attr(otel_value: OtelValue) -> Option { let safe_values: Vec = array .values .into_iter() - .filter_map(|v| v.value) - .filter_map(|v| match v { + .filter_map(|v| match v.value? { OtelValue::StringValue(s) => Some(serde_json::Value::String(s)), OtelValue::BoolValue(b) => Some(serde_json::Value::Bool(b)), OtelValue::IntValue(i) => { From 025b192f766163b61db4e1d4f6073424c54b3aa9 Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Fri, 11 Jul 2025 09:36:17 -0400 Subject: [PATCH 8/9] Update PR title again --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 191f428c41c..ab8b2c553a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Features**: - Add mechanism to allow ingestion only from trusted relays. ([#4772](https://github.com/getsentry/relay/pull/4772)) -- Serialize standalone span array attributes to JSON ([#4930](https://github.com/getsentry/relay/pull/4930)) +- Serialize OTEL span array attributes to JSON ([#4930](https://github.com/getsentry/relay/pull/4930)) **Bug Fixes**: From 010ad087269427096dccb508680c87864f14f559 Mon Sep 17 00:00:00 2001 From: George Gritsouk <989898+gggritso@users.noreply.github.com> Date: Fri, 11 Jul 2025 12:06:53 -0400 Subject: [PATCH 9/9] Update CHANGELOG.md Co-authored-by: Sebastian Zivota --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab8b2c553a7..d3a158d445b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Features**: - Add mechanism to allow ingestion only from trusted relays. ([#4772](https://github.com/getsentry/relay/pull/4772)) -- Serialize OTEL span array attributes to JSON ([#4930](https://github.com/getsentry/relay/pull/4930)) +- Serialize OTEL span array attributes to JSON. ([#4930](https://github.com/getsentry/relay/pull/4930)) **Bug Fixes**: