Skip to content

feat(otel): capture span events #795

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

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
27 changes: 27 additions & 0 deletions sentry-opentelemetry/src/converters.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::collections::BTreeMap;

use sentry_core::protocol::{value::Number, SpanId, SpanStatus, TraceId, Value};
use sentry_core::protocol::{Context, Event};

pub(crate) fn convert_span_id(span_id: &opentelemetry::SpanId) -> SpanId {
span_id.to_bytes().into()
Expand Down Expand Up @@ -54,3 +57,27 @@ pub(crate) fn convert_value(value: opentelemetry::Value) -> Value {
_ => Value::Null, // non-exhaustive
}
}

pub(crate) fn convert_event(event: &opentelemetry::trace::Event) -> Event<'static> {
let otel_context = sentry_core::protocol::OtelContext {
attributes: event
.attributes
.iter()
.map(|key_value| {
(
key_value.key.as_str().into(),
convert_value(key_value.value.clone()),
)
})
.collect(),
..Default::default()
};
let mut contexts = BTreeMap::<String, Context>::new();
contexts.insert("otel".to_owned(), otel_context.into());
Event {
level: sentry_core::Level::Error,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn’t an otel event have a level?
for tracing we have this code that does different things depending on the event level.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately in Rust they just carry a message, timestamp and attributes.
It seems that there is some misalignment in OTEL itself when it comes to this.
In e.g. Java they carry exceptions, so it makes sense to create errors out of them. @sl0thentr0py I don't think I mentioned this before when discussing this.

message: Some(event.name.to_string()),
contexts,
..Default::default()
}
}
10 changes: 7 additions & 3 deletions sentry-opentelemetry/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ use sentry_core::SentryTrace;
use sentry_core::{TransactionContext, TransactionOrSpan};

use crate::converters::{
convert_span_id, convert_span_kind, convert_span_status, convert_trace_id, convert_value,
convert_event, convert_span_id, convert_span_kind, convert_span_status, convert_trace_id,
convert_value,
};

/// A mapping from Sentry span IDs to Sentry spans/transactions.
Expand Down Expand Up @@ -152,14 +153,17 @@ impl SpanProcessor for SentrySpanProcessor {
return;
};

// TODO: read OTEL span events and convert them to Sentry breadcrumbs/events

sentry_span.set_data("otel.kind", convert_span_kind(data.span_kind));
for attribute in data.attributes {
sentry_span.set_data(attribute.key.as_str(), convert_value(attribute.value));
}
// TODO: read OTEL semantic convention span attributes and map them to the appropriate
// Sentry span attributes/context values

for event in data.events {
sentry_core::capture_event(convert_event(&event));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its a bit weird that you only get these on_end, and not when they happen.
if we decide to attach them as breadcrumbs, they should have proper ordering in relation to other breadcrumbs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true, on the other hand you know exactly which span they are in and you have the timestamp, so it shouldn't be much of a problem.

}

sentry_span.set_status(convert_span_status(&data.status));
sentry_span.finish_with_timestamp(data.end_time);
}
Expand Down