datadog_tracing/
tracer.rs

1//! Trace and layer builders to export traces to the Datadog agent.
2//!
3//! This module contains a function that builds a tracer with an exporter
4//! to send traces to the Datadog agent in batches over gRPC.
5//!
6//! It also contains a convenience function to build a layer with the tracer.
7use opentelemetry::global;
8pub use opentelemetry::trace::{TraceError, TraceId, TraceResult};
9use opentelemetry_datadog::{ApiVersion, DatadogPropagator};
10use opentelemetry_sdk::trace;
11use opentelemetry_sdk::trace::{RandomIdGenerator, Sampler, Tracer};
12use std::env;
13use std::time::Duration;
14use tracing::Subscriber;
15use tracing_opentelemetry::{OpenTelemetryLayer, PreSampledTracer};
16use tracing_subscriber::registry::LookupSpan;
17
18pub fn build_tracer() -> TraceResult<Tracer> {
19    let service_name = env::var("DD_SERVICE")
20        .map_err(|_| <&str as Into<TraceError>>::into("missing DD_SERVICE"))?;
21
22    let dd_host = env::var("DD_AGENT_HOST").unwrap_or("localhost".to_string());
23    let dd_port = env::var("DD_AGENT_PORT")
24        .ok()
25        .and_then(|it| it.parse::<i32>().ok())
26        .unwrap_or(8126);
27
28    // disabling connection reuse with dd-agent to avoid "connection closed from server" errors
29    let dd_http_client = reqwest::ClientBuilder::new()
30        .pool_idle_timeout(Duration::from_millis(1))
31        .build()
32        .expect("Could not init datadog http_client");
33
34    let tracer = opentelemetry_datadog::new_pipeline()
35        .with_http_client(dd_http_client)
36        .with_service_name(service_name)
37        .with_api_version(ApiVersion::Version05)
38        .with_agent_endpoint(format!("http://{dd_host}:{dd_port}"))
39        .with_trace_config(
40            trace::Config::default()
41                .with_sampler(Sampler::AlwaysOn)
42                .with_id_generator(RandomIdGenerator::default()),
43        )
44        .install_batch(opentelemetry_sdk::runtime::Tokio);
45
46    global::set_text_map_propagator(DatadogPropagator::default());
47
48    tracer
49}
50
51pub fn build_layer<S>() -> TraceResult<OpenTelemetryLayer<S, Tracer>>
52where
53    Tracer: opentelemetry::trace::Tracer + PreSampledTracer + 'static,
54    S: Subscriber + for<'span> LookupSpan<'span>,
55{
56    let tracer = build_tracer()?;
57    Ok(tracing_opentelemetry::layer().with_tracer(tracer))
58}