Skip to main content

otel_bootstrap/
testing.rs

1//! No-op / testing mode for `otel-bootstrap`.
2//!
3//! Enabled by the `testing` feature flag. Provides [`Telemetry::testing`], which
4//! initialises traces and metrics with in-memory, zero-network exporters so callers
5//! can init telemetry in unit and integration tests without running an OTLP collector.
6//!
7//! # Example
8//! ```rust
9//! # #[cfg(feature = "testing")]
10//! # {
11//! let handles = otel_bootstrap::Telemetry::testing("my-service");
12//! // use tracing macros freely — no collector required
13//! tracing::info!("hello from test");
14//! handles.shutdown().unwrap();
15//! # }
16//! ```
17
18use opentelemetry_sdk::{
19    metrics::SdkMeterProvider,
20    testing::{metrics::TestMetricReader, trace::NoopSpanExporter},
21    trace::SdkTracerProvider,
22};
23use tracing_subscriber::layer::SubscriberExt;
24use tracing_subscriber::util::SubscriberInitExt;
25
26use crate::{TelemetryHandles, build_resource};
27
28impl crate::Telemetry {
29    /// Initialise telemetry with in-memory, no-network exporters for use in tests.
30    ///
31    /// - Traces are routed to [`NoopSpanExporter`] via a synchronous processor — no
32    ///   batching, no I/O.
33    /// - Metrics are collected by [`TestMetricReader`] — queryable in-process, no I/O.
34    /// - No log exporter is wired up; `tracing` events still reach the `fmt` layer on
35    ///   stdout.
36    /// - The tracing subscriber is installed with [`try_init`](tracing_subscriber::util::SubscriberInitExt::try_init)
37    ///   so parallel tests that each call this function do not panic.
38    pub fn testing(service_name: &str) -> TelemetryHandles {
39        let resource = build_resource(service_name, None, None);
40
41        let tracer_provider = SdkTracerProvider::builder()
42            .with_resource(resource.clone())
43            .with_simple_exporter(NoopSpanExporter::new())
44            .build();
45
46        opentelemetry::global::set_tracer_provider(tracer_provider.clone());
47
48        let metric_reader = TestMetricReader::new();
49        let meter_provider = SdkMeterProvider::builder()
50            .with_resource(resource)
51            .with_reader(metric_reader)
52            .build();
53
54        opentelemetry::global::set_meter_provider(meter_provider.clone());
55
56        let otel_layer = tracing_opentelemetry::layer();
57        tracing_subscriber::registry()
58            .with(tracing_subscriber::EnvFilter::from_default_env())
59            .with(tracing_subscriber::fmt::layer())
60            .with(otel_layer)
61            .try_init()
62            .ok();
63
64        TelemetryHandles {
65            tracer_provider,
66            meter_provider: Some(meter_provider),
67            logger_provider: None,
68            shutdown_timeout: crate::DEFAULT_SHUTDOWN_TIMEOUT,
69            #[cfg(feature = "profiling")]
70            profiling_handle: None,
71        }
72    }
73}