use std::sync::LazyLock;
use opentelemetry::{
propagation::{text_map_propagator::FieldIter, Extractor, Injector, TextMapPropagator},
trace::TraceContextExt,
Context, SpanId, TraceId,
};
use sentry_core::parse_headers;
use sentry_core::SentryTrace;
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 sentry_trace = SentryTrace::new(
convert_trace_id(&trace_id),
convert_span_id(&span_id),
Some(sampled),
);
injector.set(SENTRY_TRACE_KEY, sentry_trace.to_string());
}
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 Some(sentry_trace) = parse_headers(pairs) {
return ctx.with_value(sentry_trace);
}
ctx.clone()
}
fn fields(&self) -> FieldIter<'_> {
FieldIter::new(&*SENTRY_PROPAGATOR_FIELDS)
}
}