Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(otlp): introduce "kind" to spans #4540

Merged
merged 9 commits into from
Mar 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
- Write resource and instrumentation scope attributes as span attributes during OTLP ingestion. ([#4533](https://github.com/getsentry/relay/pull/4533))
- Remove unused capability to block metric names and tags. ([#4536](https://github.com/getsentry/relay/pull/4536))
- Adopt new `AsyncPool` for the `EnvelopeProcessorService` and `StoreService`. ([#4520](https://github.com/getsentry/relay/pull/4520))
- Write OTLP span kind to a new `kind` field on spans. ([#4540](https://github.com/getsentry/relay/pull/4540))
- Update mapping of OTLP spans to Sentry spans in the experimental OTL traces endpoint. ([#4505](https://github.com/getsentry/relay/pull/4505))
- Expose metrics for the `AsyncPool`. ([#4538](https://github.com/getsentry/relay/pull/4538))
- Expose service utilization metrics through the internal relay metric endpoint. ([#4543](https://github.com/getsentry/relay/pull/4543))
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions relay-event-normalization/src/normalize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1783,6 +1783,7 @@ mod tests {
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
]
Expand All @@ -1804,7 +1805,7 @@ mod tests {
..Default::default()
};
normalize_app_start_spans(&mut event);
assert_debug_snapshot!(event.spans, @r#"
assert_debug_snapshot!(event.spans, @r###"
[
Span {
timestamp: ~,
Expand All @@ -1829,10 +1830,11 @@ mod tests {
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
]
"#);
"###);
}

#[test]
Expand All @@ -1850,7 +1852,7 @@ mod tests {
..Default::default()
};
normalize_app_start_spans(&mut event);
assert_debug_snapshot!(event.spans, @r#"
assert_debug_snapshot!(event.spans, @r###"
[
Span {
timestamp: ~,
Expand All @@ -1875,9 +1877,10 @@ mod tests {
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
]
"#);
"###);
}
}
1 change: 1 addition & 0 deletions relay-event-schema/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ chrono = { workspace = true, features = ["clock"] }
cookie = { workspace = true, features = ["percent-encode"] }
debugid = { workspace = true, features = ["serde"] }
enumset = { workspace = true }
opentelemetry-proto = { workspace = true, features = ["gen-tonic", "trace"] }
relay-common = { workspace = true }
relay-base-schema = { workspace = true }
relay-event-derive = { workspace = true }
Expand Down
122 changes: 121 additions & 1 deletion relay-event-schema/src/protocol/span.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
mod convert;

use std::fmt;
use std::str::FromStr;

use opentelemetry_proto::tonic::trace::v1::span::SpanKind as OtelSpanKind;
use relay_protocol::{
Annotated, Array, Empty, Error, FromValue, Getter, IntoValue, Object, Val, Value,
};
Expand Down Expand Up @@ -110,6 +114,13 @@ pub struct Span {
#[metastructure(skip_serialization = "empty")]
pub was_transaction: Annotated<bool>,

// Used to clarify the relationship between parents and children, or to distinguish between
// spans, e.g. a `server` and `client` span with the same name.
//
// See <https://opentelemetry.io/docs/specs/otel/trace/api/#spankind>
#[metastructure(skip_serialization = "empty", trim = false)]
pub kind: Annotated<SpanKind>,

// TODO remove retain when the api stabilizes
/// Additional arbitrary fields for forwards compatibility.
#[metastructure(additional_properties, retain = true, pii = "maybe")]
Expand Down Expand Up @@ -834,6 +845,113 @@ impl FromValue for Route {
}
}

#[derive(Clone, Debug, PartialEq, ProcessValue)]
#[repr(i32)]
pub enum SpanKind {
Unspecified = OtelSpanKind::Unspecified as i32,
Internal = OtelSpanKind::Internal as i32,
Server = OtelSpanKind::Server as i32,
Client = OtelSpanKind::Client as i32,
Producer = OtelSpanKind::Producer as i32,
Consumer = OtelSpanKind::Consumer as i32,
}

impl SpanKind {
pub fn as_str(&self) -> &'static str {
match self {
Self::Unspecified => "unspecified",
Self::Internal => "internal",
Self::Server => "server",
Self::Client => "client",
Self::Producer => "producer",
Self::Consumer => "consumer",
}
}
}

impl Empty for SpanKind {
fn is_empty(&self) -> bool {
false
}
}

#[derive(Debug)]
pub struct ParseSpanKindError;

impl std::str::FromStr for SpanKind {
type Err = ParseSpanKindError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"unspecified" => SpanKind::Unspecified,
"internal" => SpanKind::Internal,
"server" => SpanKind::Server,
"client" => SpanKind::Client,
"producer" => SpanKind::Producer,
"consumer" => SpanKind::Consumer,
_ => return Err(ParseSpanKindError),
})
}
}

impl Default for SpanKind {
fn default() -> Self {
Self::Internal
}
}

impl From<OtelSpanKind> for SpanKind {
fn from(otel_kind: OtelSpanKind) -> Self {
match otel_kind {
OtelSpanKind::Unspecified => Self::Unspecified,
OtelSpanKind::Internal => Self::Internal,
OtelSpanKind::Server => Self::Server,
OtelSpanKind::Client => Self::Client,
OtelSpanKind::Producer => Self::Producer,
OtelSpanKind::Consumer => Self::Consumer,
}
}
}

impl fmt::Display for SpanKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}

impl FromValue for SpanKind {
fn from_value(value: Annotated<Value>) -> Annotated<Self>
where
Self: Sized,
{
match value {
Annotated(Some(Value::String(s)), meta) => Annotated(SpanKind::from_str(&s).ok(), meta),
Annotated(_, meta) => Annotated(None, meta),
}
}
}

impl IntoValue for SpanKind {
fn into_value(self) -> Value
where
Self: Sized,
{
Value::String(self.to_string())
}

fn serialize_payload<S>(
&self,
s: S,
_behavior: relay_protocol::SkipSerialization,
) -> Result<S::Ok, S::Error>
where
Self: Sized,
S: serde::Serializer,
{
s.serialize_str(self.as_str())
}
}

#[cfg(test)]
mod tests {
use crate::protocol::Measurement;
Expand Down Expand Up @@ -874,7 +992,8 @@ mod tests {
"value": 9001.0,
"unit": "byte"
}
}
},
"kind": "server"
}"#;
let mut measurements = Object::new();
measurements.insert(
Expand Down Expand Up @@ -915,6 +1034,7 @@ mod tests {
span_id: Annotated::new(SpanId("fa90fdead5f74052".into())),
status: Annotated::new(SpanStatus::Ok),
origin: Annotated::new("auto.http".to_owned()),
kind: Annotated::new(SpanKind::Server),
measurements: Annotated::new(Measurements(measurements)),
links,
..Default::default()
Expand Down
2 changes: 2 additions & 0 deletions relay-event-schema/src/protocol/span/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ impl From<&Event> for Span {
measurements: measurements.clone(),
platform: platform.clone(),
was_transaction: true.into(),
kind: Default::default(),
other: Default::default(),
}
}
Expand Down Expand Up @@ -271,6 +272,7 @@ mod tests {
),
platform: "php",
was_transaction: true,
kind: ~,
other: {},
}
"###);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
Span {
Expand Down Expand Up @@ -270,6 +271,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
),
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
Span {
Expand Down Expand Up @@ -354,6 +356,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
Span {
Expand Down Expand Up @@ -438,6 +441,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
Span {
Expand Down Expand Up @@ -522,6 +526,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
Span {
Expand Down Expand Up @@ -606,6 +611,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
Span {
Expand Down Expand Up @@ -763,6 +769,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
Span {
Expand Down Expand Up @@ -920,6 +927,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
Span {
Expand Down Expand Up @@ -1004,6 +1012,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
Span {
Expand Down Expand Up @@ -1161,6 +1170,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
Span {
Expand Down Expand Up @@ -1318,6 +1328,7 @@ expression: "(&event.value().unwrap().spans, metrics.project_metrics)"
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
],
Expand Down
5 changes: 3 additions & 2 deletions relay-server/src/metrics_extraction/transactions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ mod tests {
};

let extracted = extractor.extract(event.value().unwrap()).unwrap();
insta::assert_debug_snapshot!(event.value().unwrap().spans, @r#"
insta::assert_debug_snapshot!(event.value().unwrap().spans, @r###"
[
Span {
timestamp: Timestamp(
Expand Down Expand Up @@ -651,10 +651,11 @@ mod tests {
measurements: ~,
platform: ~,
was_transaction: ~,
kind: ~,
other: {},
},
]
"#);
"###);

insta::assert_debug_snapshot!(extracted.project_metrics, @r###"
[
Expand Down
2 changes: 2 additions & 0 deletions relay-server/src/services/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1348,6 +1348,8 @@ struct SpanKafkaMessage<'a> {

#[serde(default, skip_serializing_if = "none_or_empty_object")]
data: Option<&'a RawValue>,
#[serde(default, skip_serializing_if = "Option::is_none")]
kind: Option<&'a str>,
#[serde(borrow, default, skip_serializing_if = "Option::is_none")]
measurements: Option<BTreeMap<Cow<'a, str>, Option<SpanMeasurement>>>,
#[serde(default)]
Expand Down
Loading