-
Notifications
You must be signed in to change notification settings - Fork 97
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
base: master
Are you sure you want to change the base?
Conversation
OTLP spans have a property called `kind` that helps specify the relationship between that span and its parent or child. Sentry users should be able to see the span kind and search/filter on it when it is sent. During ingestion, write a string representation of the `kind` to the `span.kind` attribute. (A string representation is chosen over the default integer one because it is both self-describing and also makes search straightforward (no need for translations between string and integer in the frontend or EAP. We are relying on Clickhouse's compression to make the additional data usage reasonable.) [0] https://github.com/open-telemetry/opentelemetry-proto/blob/d7770822d70c7bd47a6891fc9faacc66fc4af3d3/opentelemetry/proto/trace/v1/trace.proto#L152-L178 Co-authored-by: Ash Anand <[email protected]>
#[metastructure(field = "span.kind")] | ||
pub span_kind: Annotated<String>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a small doc string, ideally what values it can have and when it should be filled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See opentelemetry-proto:
// Distinguishes between spans generated in a particular context. For example,
// two spans with the same name may be distinguished using `CLIENT` (caller)
// and `SERVER` (callee) to identify queueing latency associated with the span.
relay-spans/src/span.rs
Outdated
@@ -201,6 +202,11 @@ pub fn otel_to_sentry_span(otel_span: OtelSpan) -> EventSpan { | |||
description = Some(format!("{http_method} {http_route}")); | |||
} | |||
|
|||
data.insert( | |||
"span.kind".to_owned(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In opentelemetry-proto this is a top-level field on the span rather than an attribute. Could we align with their schema and create a field on our Span
, too? Note we did the same with is_remote
(mapping it out from flags
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jan-auer Can do. Just to confirm, I'm assuming that would mean adding kind
as a field to both Span
and SpanKafkaMessage
for transfer to Snuba? (And then EAP can choose to store it however it makes sense, column or attribute?)
Also, in that case the choice of how to save the value is being made by EAP instead - in that case should we transfer it as the original integer value rather than our string representation, maybe? (Leaving it to Snuba to stringify, in storage or via RPC?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that would mean adding kind as a field to both Span and SpanKafkaMessage for transfer to Snuba?
That's right.
And then EAP can choose to store it however it makes sense, column or attribute?
We can consider aligning with how we want kind
to show up in the product & how otel SDKs track it. In my previous comment, I assumed we would then also show it as span.kind
rather than span.data.kind
. If we want to show it as an attribute, then we should probably keep your current approach. Otherwise, we have a strange drift between the SDK protocol, pipeline, and the product-side data model.
in that case should we transfer it as the original integer value rather than our string representation, maybe?
Definitely possible, though I'd advise against it in this instance. In both cases - string or integer - would need to share an enum between Relay, Sentry (pipeline) and Snuba. However, if we convert to string representation right away, we can now use the same enums in the processing pipeline and in all workers/endpoints that pull data out of EAP. Essentially, the pre- and post-EAP data model would be identical, which I think would be desirable.
@jan-auer I've updated the PR to use a new |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I think using the string representation as a top-level field is the right choice.
// | ||
// See <https://opentelemetry.io/docs/specs/otel/trace/api/#spankind> | ||
#[metastructure(skip_serialization = "empty", trim = false)] | ||
pub kind: Annotated<String>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that suggestion, more strong types are always good down the road 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback, I'll make that change 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jan-auer @Dav1dde I've updated the PR to use an enum.
I used a From<i32>
implementation in c86423b. The only thing I didn't like about this implementation was that we lost the match
on opentelemetry-proto
's SpanKind
enum (henceforth OtelSpanKind
) - in other words, we would no longer be notified (due to exhaustiveness checking) if new kind values were added upstream in the future.
You can see in commit 2f764bc my changes to instead use From<OtelSpanKind>
, effectively first transforming the value from the incoming i32
to OtelSpanKind
, then to our own SpanLink
type. This gives us an exhaustiveness check on OtelSpanKind
matches again, and even though the code to read kind
in otel_to_sentry_span
became a bit longer, I personally like the explicitness of the second in this particular context.
// From<i32> version
kind: SpanKind::from(kind).into(),
vs
// From<OtelSpanKind> version
kind: OtelSpanKind::try_from(kind)
.map_or(SpanKind::Unspecified, SpanKind::from)
.into(),
I can always revert the second commit to get back to the more direct i32
check if you prefer. Curious if you have a preference either way.
7dff9eb
to
b9b95b7
Compare
b9b95b7
to
2f764bc
Compare
OTLP spans have a property called
kind
that helps specify the relationship between that span and its parent or child. Sentry users should be able to see the span kind and search/filter on it when it is sent (via OTLP or theOtelSpan
envelope item type). During ingestion, write a string representation of thekind
to thespan.kind
attribute.(A string representation is chosen over the default integer one because it is both self-describing and also makes search straightforward (no need for translations between string and integer in the frontend or EAP. We are relying on Clickhouse's compression to make the additional data usage reasonable.)