use opentelemetry::Context;
use opentelemetry::KeyValue;
use opentelemetry::trace::SpanContext;
use super::layer::WithContext;
pub(crate) trait OpenTelemetrySpanExt {
fn add_link(&self, cx: SpanContext);
fn add_link_with_attributes(&self, cx: SpanContext, attributes: Vec<KeyValue>);
fn context(&self) -> Context;
}
impl OpenTelemetrySpanExt for tracing::Span {
fn add_link(&self, cx: SpanContext) {
self.add_link_with_attributes(cx, Vec::new())
}
fn add_link_with_attributes(&self, cx: SpanContext, attributes: Vec<KeyValue>) {
if cx.is_valid() {
let mut cx = Some(cx);
let mut att = Some(attributes);
self.with_subscriber(move |(id, subscriber)| {
if let Some(get_context) = subscriber.downcast_ref::<WithContext>() {
get_context.with_context(subscriber, id, move |data, _tracer| {
if let Some(cx) = cx.take() {
let attr = att.take().unwrap_or_default();
let follows_link = opentelemetry::trace::Link::new(cx, attr);
data.builder
.links
.get_or_insert_with(|| Vec::with_capacity(1))
.push(follows_link);
}
});
}
});
}
}
fn context(&self) -> Context {
let mut cx = None;
self.with_subscriber(|(id, subscriber)| {
if let Some(get_context) = subscriber.downcast_ref::<WithContext>() {
get_context.with_context(subscriber, id, |builder, tracer| {
cx = Some(tracer.sampled_context(builder));
})
}
});
cx.unwrap_or_default()
}
}