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}