use opentelemetry::trace::{SpanId, TraceId};
use tracing::Subscriber;
use tracing_opentelemetry::OtelData;
use tracing_subscriber::{layer::Context, registry::LookupSpan};
#[derive(serde::Serialize)]
#[cfg_attr(test, derive(Debug, Clone, Copy, serde::Deserialize, PartialEq, Eq))]
pub struct DatadogTraceId(pub(crate) u64);
#[allow(clippy::fallible_impl_from)]
impl From<TraceId> for DatadogTraceId {
fn from(value: TraceId) -> Self {
let bytes = value.to_bytes();
#[allow(clippy::unwrap_used)]
let most_significant_8_bytes = bytes.get(8..16).unwrap();
#[allow(clippy::unwrap_used)]
let bytes_as_sized_slice: [u8; 8] = most_significant_8_bytes.try_into().unwrap();
Self(u64::from_be_bytes(bytes_as_sized_slice))
}
}
#[derive(serde::Serialize)]
#[cfg_attr(test, derive(Debug, Clone, Copy, serde::Deserialize, PartialEq, Eq))]
pub struct DatadogSpanId(pub u64);
impl From<SpanId> for DatadogSpanId {
fn from(value: SpanId) -> Self {
Self(u64::from_be_bytes(value.to_bytes()))
}
}
pub fn read_from_context<S>(ctx: &Context<'_, S>) -> Option<(DatadogTraceId, DatadogSpanId)>
where
S: Subscriber + for<'a> LookupSpan<'a>,
{
ctx.lookup_current().and_then(|span_ref| {
span_ref.extensions().get::<OtelData>().map(|otel| {
let trace_id = otel.trace_id().unwrap_or(TraceId::INVALID);
let span_id = otel.span_id().unwrap_or(SpanId::INVALID);
(trace_id.into(), span_id.into())
})
})
}