opentelemetry_sdk/trace/in_memory_exporter.rs
1use crate::error::{OTelSdkError, OTelSdkResult};
2use crate::resource::Resource;
3use crate::trace::{SpanData, SpanExporter};
4use crate::InMemoryExporterError;
5use std::sync::{Arc, Mutex};
6use std::time::Duration;
7
8/// An in-memory span exporter that stores span data in memory.
9///
10/// This exporter is useful for testing and debugging purposes. It stores
11/// metric data in a `Vec<SpanData>`. Metrics can be retrieved
12/// using the `get_finished_spans` method.
13/// # Example
14/// ```
15///# use opentelemetry::trace::{SpanKind, TraceContextExt};
16///# use opentelemetry::{global, trace::Tracer, Context};
17///# use opentelemetry_sdk::propagation::TraceContextPropagator;
18///# use opentelemetry_sdk::runtime;
19///# use opentelemetry_sdk::trace::InMemorySpanExporterBuilder;
20///# use opentelemetry_sdk::trace::{BatchSpanProcessor, SdkTracerProvider};
21///
22///# #[tokio::main]
23///# async fn main() {
24///     let exporter = InMemorySpanExporterBuilder::new().build();
25///     let provider = SdkTracerProvider::builder()
26///         .with_span_processor(BatchSpanProcessor::builder(exporter.clone()).build())
27///         .build();
28///
29///     global::set_tracer_provider(provider.clone());
30///
31///     let tracer = global::tracer("example/in_memory_exporter");
32///     let span = tracer
33///         .span_builder("say hello")
34///         .with_kind(SpanKind::Server)
35///         .start(&tracer);
36///
37///     let cx = Context::current_with_span(span);
38///     cx.span().add_event("handling this...", Vec::new());
39///     cx.span().end();
40///
41///     if let Err(e) = provider.force_flush() {
42///         println!("{:?}", e)
43///     }
44///     let spans = exporter.get_finished_spans().unwrap();
45///     for span in spans {
46///         println!("{:?}", span)
47///     }
48///# }
49/// ```
50#[derive(Clone, Debug)]
51pub struct InMemorySpanExporter {
52    spans: Arc<Mutex<Vec<SpanData>>>,
53    resource: Arc<Mutex<Resource>>,
54}
55
56impl Default for InMemorySpanExporter {
57    fn default() -> Self {
58        InMemorySpanExporterBuilder::new().build()
59    }
60}
61
62/// Builder for [`InMemorySpanExporter`].
63/// # Example
64/// ```
65///# use opentelemetry_sdk::trace::InMemorySpanExporterBuilder;
66///
67/// let exporter = InMemorySpanExporterBuilder::new().build();
68/// ```
69#[derive(Clone, Debug)]
70pub struct InMemorySpanExporterBuilder {}
71
72impl Default for InMemorySpanExporterBuilder {
73    fn default() -> Self {
74        Self::new()
75    }
76}
77
78impl InMemorySpanExporterBuilder {
79    /// Creates a new instance of the `InMemorySpanExporterBuilder`.
80    pub fn new() -> Self {
81        Self {}
82    }
83
84    /// Creates a new instance of the `InMemorySpanExporter`.
85    pub fn build(&self) -> InMemorySpanExporter {
86        InMemorySpanExporter {
87            spans: Arc::new(Mutex::new(Vec::new())),
88            resource: Arc::new(Mutex::new(Resource::builder().build())),
89        }
90    }
91}
92
93impl InMemorySpanExporter {
94    /// Returns the finished span as a vector of `SpanData`.
95    ///
96    /// # Errors
97    ///
98    /// Returns a `TraceError` if the internal lock cannot be acquired.
99    ///
100    /// # Example
101    ///
102    /// ```
103    /// # use opentelemetry_sdk::trace::InMemorySpanExporter;
104    ///
105    /// let exporter = InMemorySpanExporter::default();
106    /// let finished_spans = exporter.get_finished_spans().unwrap();
107    /// ```
108    pub fn get_finished_spans(&self) -> Result<Vec<SpanData>, InMemoryExporterError> {
109        let spans = self
110            .spans
111            .lock()
112            .map(|spans_guard| spans_guard.iter().cloned().collect())
113            .map_err(InMemoryExporterError::from)?;
114        Ok(spans)
115    }
116
117    /// Clears the internal storage of finished spans.
118    ///
119    /// # Example
120    ///
121    /// ```
122    /// # use opentelemetry_sdk::trace::InMemorySpanExporter;
123    ///
124    /// let exporter = InMemorySpanExporter::default();
125    /// exporter.reset();
126    /// ```
127    pub fn reset(&self) {
128        let _ = self.spans.lock().map(|mut spans_guard| spans_guard.clear());
129    }
130}
131
132impl SpanExporter for InMemorySpanExporter {
133    async fn export(&self, batch: Vec<SpanData>) -> OTelSdkResult {
134        let result = self
135            .spans
136            .lock()
137            .map(|mut spans_guard| spans_guard.append(&mut batch.clone()))
138            .map_err(|err| {
139                OTelSdkError::InternalFailure(format!("Failed to lock spans: {:?}", err))
140            });
141        result
142    }
143
144    fn shutdown_with_timeout(&mut self, _timeout: Duration) -> OTelSdkResult {
145        self.reset();
146        Ok(())
147    }
148
149    fn set_resource(&mut self, resource: &Resource) {
150        self.resource
151            .lock()
152            .map(|mut res_guard| *res_guard = resource.clone())
153            .expect("Resource lock poisoned");
154    }
155}