1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
use crate::layer::WithContext;
use opentelemetry::Context;
/// Utility functions to allow tracing [`Span`]s to accept and return
/// [OpenTelemetry] [`Context`]s.
///
/// [`Span`]: https://docs.rs/tracing/latest/tracing/struct.Span.html
/// [OpenTelemetry]: https://opentelemetry.io
/// [`Context`]: opentelemetry::Context
pub trait OpenTelemetrySpanExt {
/// Associates `self` with a given OpenTelemetry trace, using the provided
/// parent [`Context`].
///
/// [`Context`]: opentelemetry::Context
///
/// # Examples
///
/// ```rust
/// use opentelemetry::{propagation::TextMapPropagator, trace::TraceContextExt};
/// use opentelemetry::sdk::propagation::TraceContextPropagator;
/// use tracing_opentelemetry::OpenTelemetrySpanExt;
/// use std::collections::HashMap;
/// use tracing::Span;
///
/// // Example carrier, could be a framework header map that impls otel's `Extract`.
/// let mut carrier = HashMap::new();
///
/// // Propagator can be swapped with b3 propagator, jaeger propagator, etc.
/// let propagator = TraceContextPropagator::new();
///
/// // Extract otel parent context via the chosen propagator
/// let parent_context = propagator.extract(&carrier);
///
/// // Generate a tracing span as usual
/// let app_root = tracing::span!(tracing::Level::INFO, "app_start");
///
/// // Assign parent trace from external context
/// app_root.set_parent(parent_context.clone());
///
/// // Or if the current span has been created elsewhere:
/// Span::current().set_parent(parent_context);
/// ```
fn set_parent(&self, cx: Context);
/// Extracts an OpenTelemetry [`Context`] from `self`.
///
/// [`Context`]: opentelemetry::Context
///
/// # Examples
///
/// ```rust
/// use opentelemetry::Context;
/// use tracing_opentelemetry::OpenTelemetrySpanExt;
/// use tracing::Span;
///
/// fn make_request(cx: Context) {
/// // perform external request after injecting context
/// // e.g. if the request's headers impl `opentelemetry::propagation::Injector`
/// // then `propagator.inject_context(cx, request.headers_mut())`
/// }
///
/// // Generate a tracing span as usual
/// let app_root = tracing::span!(tracing::Level::INFO, "app_start");
///
/// // To include tracing context in client requests from _this_ app,
/// // extract the current OpenTelemetry context.
/// make_request(app_root.context());
///
/// // Or if the current span has been created elsewhere:
/// make_request(Span::current().context())
/// ```
fn context(&self) -> Context;
}
impl OpenTelemetrySpanExt for tracing::Span {
fn set_parent(&self, cx: Context) {
let mut cx = Some(cx);
self.with_subscriber(move |(id, subscriber)| {
if let Some(get_context) = subscriber.downcast_ref::<WithContext>() {
get_context.with_context(subscriber, id, move |builder, _tracer| {
if let Some(cx) = cx.take() {
builder.parent_context = cx;
}
});
}
});
}
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()
}
}