use std::sync::LazyLock;
use opentelemetry::{
propagation::{text_map_propagator::FieldIter, Extractor, Injector, TextMapPropagator},
trace::TraceContextExt,
Context, SpanId, TraceId,
};
use sentry_core::TracePropagationContext;
use crate::converters::{convert_span_id, convert_trace_id};
const SENTRY_TRACE_KEY: &str = "sentry-trace";
static SENTRY_PROPAGATOR_FIELDS: LazyLock<[String; 1]> =
LazyLock::new(|| [SENTRY_TRACE_KEY.to_owned()]);
#[derive(Debug, Copy, Clone)]
pub struct SentryPropagator {}
impl SentryPropagator {
pub fn new() -> Self {
Self {}
}
}
impl Default for SentryPropagator {
fn default() -> Self {
Self::new()
}
}
impl TextMapPropagator for SentryPropagator {
fn inject_context(&self, ctx: &Context, injector: &mut dyn Injector) {
let trace_id = ctx.span().span_context().trace_id();
let span_id = ctx.span().span_context().span_id();
let sampled = ctx.span().span_context().is_sampled();
if trace_id == TraceId::INVALID || span_id == SpanId::INVALID {
return;
}
let trace_context =
TracePropagationContext::new(convert_trace_id(&trace_id), convert_span_id(&span_id))
.with_sampled(sampled);
injector.set(SENTRY_TRACE_KEY, trace_context.sentry_trace_header());
}
fn extract_with_context(&self, ctx: &Context, extractor: &dyn Extractor) -> Context {
let keys = extractor.keys();
let pairs = keys
.iter()
.filter_map(|&key| extractor.get(key).map(|value| (key, value)));
if let Ok(trace_context) = TracePropagationContext::try_from_headers(pairs) {
return ctx.with_value(trace_context);
}
ctx.clone()
}
fn fields(&self) -> FieldIter<'_> {
FieldIter::new(&*SENTRY_PROPAGATOR_FIELDS)
}
}