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}