init-tracing-opentelemetry 0.38.1

A set of helpers to initialize (and more) tracing + opentelemetry (compose your own or use opinionated preset)
Documentation
//#![warn(missing_docs)]
#![forbid(unsafe_code)]
#![warn(clippy::perf)]
#![warn(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::missing_errors_doc)]
#![doc = include_str!("../README.md")]
#![cfg_attr(docs_rs, feature(doc_cfg))]

pub use opentelemetry;
pub use opentelemetry_sdk;
pub use tracing_opentelemetry;

mod error;
pub use error::Error;

use opentelemetry::propagation::{TextMapCompositePropagator, TextMapPropagator};
use opentelemetry_sdk::propagation::{BaggagePropagator, TraceContextPropagator};

#[cfg(feature = "tracing_subscriber_ext")]
#[cfg_attr(docs_rs, doc(cfg(feature = "tracing_subscriber_ext")))]
pub mod config;
#[cfg(feature = "tracing_subscriber_ext")]
#[cfg_attr(docs_rs, doc(cfg(feature = "tracing_subscriber_ext")))]
pub mod formats;
#[cfg(feature = "otlp")]
#[cfg_attr(docs_rs, doc(cfg(feature = "otlp")))]
pub mod otlp;
#[cfg(feature = "tracer")]
#[cfg_attr(docs_rs, doc(cfg(feature = "tracer")))]
pub mod resource;
#[cfg(feature = "stdout")]
#[cfg_attr(docs_rs, doc(cfg(feature = "stdout")))]
pub mod stdio;
#[cfg(feature = "tracing_subscriber_ext")]
#[cfg_attr(docs_rs, doc(cfg(feature = "tracing_subscriber_ext")))]
pub mod tracing_subscriber_ext;

/// Configure the global propagator based on content of the env variable [OTEL_PROPAGATORS](https://opentelemetry.io/docs/concepts/sdk-configuration/general-sdk-configuration/#otel_propagators)
/// Specifies Propagators to be used in a comma-separated list.
/// Default value: `"tracecontext,baggage"`
/// Example: `export OTEL_PROPAGATORS="b3"`
/// Accepted values for `OTEL_PROPAGATORS` are:
///
/// - "tracecontext": W3C Trace Context
/// - "baggage": W3C Baggage
/// - "b3": B3 Single (require feature "zipkin")
/// - "b3multi": B3 Multi (require feature "zipkin")
/// - "jaeger": Jaeger (require feature "jaeger")
/// - "xray": AWS X-Ray (require feature "xray")
/// - "ottrace": OT Trace (third party) (not supported)
/// - "none": No automatically configured propagator.
///
/// # Errors
///
/// Will return `TraceError` if issue in reading or instanciate propagator.
pub fn init_propagator() -> Result<(), Error> {
    let value_from_env =
        std::env::var("OTEL_PROPAGATORS").unwrap_or_else(|_| "tracecontext,baggage".to_string());
    let propagators: Vec<(Box<dyn TextMapPropagator + Send + Sync>, String)> = value_from_env
        .split(',')
        .map(|s| {
            let name = s.trim().to_lowercase();
            propagator_from_string(&name).map(|o| o.map(|b| (b, name)))
        })
        .collect::<Result<Vec<_>, _>>()?
        .into_iter()
        .flatten()
        .collect();
    if !propagators.is_empty() {
        let (propagators_impl, propagators_name): (Vec<_>, Vec<_>) =
            propagators.into_iter().unzip();
        tracing::debug!(target: "otel::setup", OTEL_PROPAGATORS = propagators_name.join(","));
        let composite_propagator = TextMapCompositePropagator::new(propagators_impl);
        opentelemetry::global::set_text_map_propagator(composite_propagator);
    }
    Ok(())
}

#[allow(clippy::box_default)]
fn propagator_from_string(
    v: &str,
) -> Result<Option<Box<dyn TextMapPropagator + Send + Sync>>, Error> {
    match v {
        "tracecontext" => Ok(Some(Box::new(TraceContextPropagator::new()))),
        "baggage" => Ok(Some(Box::new(BaggagePropagator::new()))),
        #[cfg(feature = "zipkin")]
        "b3" => Ok(Some(Box::new(
            opentelemetry_zipkin::Propagator::with_encoding(
                opentelemetry_zipkin::B3Encoding::SingleHeader,
            ),
        ))),
        #[cfg(not(feature = "zipkin"))]
        "b3" => Err(Error::SetupError(
            "unsupported propagators form env OTEL_PROPAGATORS: 'b3', try to enable compile feature 'zipkin'".to_string(),
        )),
        #[cfg(feature = "zipkin")]
        "b3multi" => Ok(Some(Box::new(
            opentelemetry_zipkin::Propagator::with_encoding(
                opentelemetry_zipkin::B3Encoding::MultipleHeader,
            ),
        ))),
        #[cfg(not(feature = "zipkin"))]
        "b3multi" => Err(Error::SetupError(
            "unsupported propagators form env OTEL_PROPAGATORS: 'b3multi', try to enable compile feature 'zipkin'".to_string(),
        )),
        #[cfg(feature = "jaeger")]
        "jaeger" => Ok(Some(Box::new(
            opentelemetry_jaeger_propagator::Propagator::default(),
        ))),
        #[cfg(not(feature = "jaeger"))]
        "jaeger" => Err(Error::SetupError(
            "unsupported propagators form env OTEL_PROPAGATORS: 'jaeger', try to enable compile feature 'jaeger'".to_string(),
        )),
        #[cfg(feature = "xray")]
        "xray" => Ok(Some(Box::new(
            opentelemetry_aws::trace::XrayPropagator::default(),
        ))),
        #[cfg(not(feature = "xray"))]
        "xray" => Err(Error::SetupError(
            "unsupported propagators form env OTEL_PROPAGATORS: 'xray', try to enable compile feature 'xray'".to_string(),
        )),
        "none" => Ok(None),
        unknown => Err(Error::SetupError(format!(
            "unsupported propagators form env OTEL_PROPAGATORS: '{unknown}'"
        ))),
    }
}

// Re-export the new configuration API for easier access
#[cfg(feature = "tracing_subscriber_ext")]
pub use config::{
    FeatureSet, Guard, LevelConfig, LogFormat, LogTimer, OtelConfig, TracingConfig, WriterConfig,
};

#[cfg(feature = "tracing_subscriber_ext")]
pub use formats::{
    CompactLayerBuilder, FullLayerBuilder, JsonLayerBuilder, LayerBuilder, PrettyLayerBuilder,
};

#[cfg(all(feature = "tracing_subscriber_ext", feature = "logfmt"))]
pub use formats::LogfmtLayerBuilder;

#[cfg(test)]
#[cfg(feature = "tracer")]
mod tests {
    use assert2::assert;

    #[test]
    fn init_tracing_failed_on_invalid_propagator() {
        assert!(let Err(_) = super::propagator_from_string("xxxxxx"));

        // std::env::set_var("OTEL_PROPAGATORS", "xxxxxx");
        // dbg!(std::env::var("OTEL_PROPAGATORS"));
        // assert!(let Err(_) = init_tracing());
    }
}