mod args;
mod grpc;
mod memory_telemetry;
mod metrics_server;
mod prometheus;
mod shared_reader;
mod telemetry;
mod trace_id_format;
mod tracestate;
mod tracing_session;
mod utils;
use std::collections::HashMap;
use opentelemetry_sdk::propagation::TraceContextPropagator;
pub use self::args::{LogFormat, TelemetryArgs};
pub use self::grpc::{
ClientOnResponse, ClientTelemetryLayer, GrpcMakeSpan, GrpcOnEos, GrpcOnFirstBodyChunk,
GrpcOnRequest, GrpcOnResponse, GrpcOnResponseOptions, ServerTelemetryLayer,
SpanMetadataCleanupLayer, TelemetryLayerOptions, TracingInjectorInterceptor,
new_client_telemetry_layer, new_server_telemetry_layer,
};
pub use self::telemetry::{Telemetry, TelemetryDropBehavior, is_telemetry_active};
pub use self::utils::to_short_str;
pub use self::tracing_session::{
RERUN_SESSION_TRACESTATE_KEY, RerunTracingSessionId, current_rerun_session_id,
dec_active_tracing_session_count, inc_active_tracing_session_count,
with_current_tracing_session, with_tracing_session,
};
#[cfg(feature = "session_id_reader")]
pub use self::tracing_session::SessionIdReader;
pub mod external {
#[cfg(feature = "tracy")]
pub use tracing_tracy;
pub use {clap, opentelemetry, tower, tower_http, tracing, tracing_opentelemetry};
}
pub fn current_trace_id() -> Option<opentelemetry::TraceId> {
use opentelemetry::trace::TraceContextExt as _;
use tracing_opentelemetry::OpenTelemetrySpanExt as _;
let cx = tracing::Span::current().context();
let span = cx.span();
let span_cx = span.span_context();
(span_cx.is_valid() && span_cx.is_sampled()).then(|| span_cx.trace_id())
}
pub fn current_trace_headers() -> Option<TraceHeaders> {
use opentelemetry::propagation::text_map_propagator::TextMapPropagator as _;
use opentelemetry::trace::TraceContextExt as _;
use tracing_opentelemetry::OpenTelemetrySpanExt as _;
let cx = tracing::Span::current().context();
let span = cx.span();
let span_cx = span.span_context();
if !span_cx.is_valid() || !span_cx.is_sampled() {
return None;
}
let propagator = TraceContextPropagator::new();
let mut carrier = TraceHeaders::empty();
propagator.inject_context(&cx, &mut carrier);
Some(carrier)
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TraceHeaders {
pub traceparent: String,
pub tracestate: Option<String>,
}
impl TraceHeaders {
pub const TRACEPARENT_KEY: &'static str = "traceparent";
pub const TRACESTATE_KEY: &'static str = "tracestate";
pub fn empty() -> Self {
Self {
traceparent: String::new(),
tracestate: None,
}
}
pub fn tracestate(&self) -> HashMap<String, String> {
self.tracestate
.as_ref()
.map(|s| crate::tracestate::parse_pairs(s))
.unwrap_or_default()
}
}
impl TraceHeaders {
#[must_use]
pub fn attach(&self) -> Option<opentelemetry::ContextGuard> {
if self.traceparent.is_empty() {
None
} else {
let parent_ctx =
opentelemetry::global::get_text_map_propagator(|prop| prop.extract(self));
Some(parent_ctx.attach())
}
}
}
impl opentelemetry::propagation::Injector for TraceHeaders {
fn set(&mut self, key: &str, value: String) {
match key {
Self::TRACEPARENT_KEY => self.traceparent = value,
Self::TRACESTATE_KEY if !value.is_empty() => {
self.tracestate = Some(value);
}
_ => {}
}
}
}
impl opentelemetry::propagation::Extractor for TraceHeaders {
fn get(&self, key: &str) -> Option<&str> {
match key {
Self::TRACEPARENT_KEY => Some(self.traceparent.as_str()),
Self::TRACESTATE_KEY => self.tracestate.as_deref(),
_ => None,
}
}
fn keys(&self) -> Vec<&str> {
vec![Self::TRACEPARENT_KEY, Self::TRACESTATE_KEY]
}
}
impl From<&TraceHeaders> for opentelemetry::Context {
fn from(value: &TraceHeaders) -> Self {
use opentelemetry::propagation::text_map_propagator::TextMapPropagator as _;
let propagator = TraceContextPropagator::new();
propagator.extract(value)
}
}
pub trait EnvFilterExt
where
Self: Sized,
{
fn add_directive_if_absent(
self,
base: &str,
target: &str,
default: &str,
) -> anyhow::Result<Self>;
}
impl EnvFilterExt for tracing_subscriber::EnvFilter {
fn add_directive_if_absent(
self,
base: &str,
target: &str,
default: &str,
) -> anyhow::Result<Self> {
if base.contains(&format!("{target}=")) {
Ok(self)
} else {
let filter = self.add_directive(format!("{target}={default}").parse()?);
Ok(filter)
}
}
}