opentelemetry_sdk/testing/trace/
span_exporters.rs

1use crate::error::{OTelSdkError, OTelSdkResult};
2use crate::{
3    trace::{SpanData, SpanExporter},
4    trace::{SpanEvents, SpanLinks},
5    ExportError,
6};
7pub use opentelemetry::testing::trace::TestSpan;
8use opentelemetry::{
9    trace::{SpanContext, SpanId, SpanKind, Status, TraceFlags, TraceId, TraceState},
10    InstrumentationScope,
11};
12use std::fmt::{Display, Formatter};
13
14pub fn new_test_export_span_data() -> SpanData {
15    SpanData {
16        span_context: SpanContext::new(
17            TraceId::from_u128(1),
18            SpanId::from_u64(1),
19            TraceFlags::SAMPLED,
20            false,
21            TraceState::default(),
22        ),
23        parent_span_id: SpanId::INVALID,
24        span_kind: SpanKind::Internal,
25        name: "opentelemetry".into(),
26        start_time: opentelemetry::time::now(),
27        end_time: opentelemetry::time::now(),
28        attributes: Vec::new(),
29        dropped_attributes_count: 0,
30        events: SpanEvents::default(),
31        links: SpanLinks::default(),
32        status: Status::Unset,
33        instrumentation_scope: InstrumentationScope::default(),
34    }
35}
36
37#[derive(Debug)]
38pub struct TokioSpanExporter {
39    tx_export: tokio::sync::mpsc::UnboundedSender<SpanData>,
40    tx_shutdown: tokio::sync::mpsc::UnboundedSender<()>,
41}
42
43impl SpanExporter for TokioSpanExporter {
44    async fn export(&self, batch: Vec<SpanData>) -> OTelSdkResult {
45        batch.into_iter().try_for_each(|span_data| {
46            self.tx_export
47                .send(span_data)
48                .map_err(|err| OTelSdkError::InternalFailure(format!("Export failed: {:?}", err)))
49        })
50    }
51
52    fn shutdown(&mut self) -> OTelSdkResult {
53        self.tx_shutdown.send(()).map_err(|_| {
54            OTelSdkError::InternalFailure("Failed to send shutdown signal".to_string())
55        })
56    }
57}
58
59pub fn new_tokio_test_exporter() -> (
60    TokioSpanExporter,
61    tokio::sync::mpsc::UnboundedReceiver<SpanData>,
62    tokio::sync::mpsc::UnboundedReceiver<()>,
63) {
64    let (tx_export, rx_export) = tokio::sync::mpsc::unbounded_channel();
65    let (tx_shutdown, rx_shutdown) = tokio::sync::mpsc::unbounded_channel();
66    let exporter = TokioSpanExporter {
67        tx_export,
68        tx_shutdown,
69    };
70    (exporter, rx_export, rx_shutdown)
71}
72
73#[derive(Debug)]
74pub struct TestExportError(String);
75
76impl std::error::Error for TestExportError {}
77
78impl ExportError for TestExportError {
79    fn exporter_name(&self) -> &'static str {
80        "test"
81    }
82}
83
84impl Display for TestExportError {
85    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
86        write!(f, "{}", self.0)
87    }
88}
89
90#[cfg(any(feature = "rt-tokio", feature = "rt-tokio-current-thread"))]
91impl<T> From<tokio::sync::mpsc::error::SendError<T>> for TestExportError {
92    fn from(err: tokio::sync::mpsc::error::SendError<T>) -> Self {
93        TestExportError(err.to_string())
94    }
95}
96
97/// A no-op instance of an [`SpanExporter`].
98///
99/// [`SpanExporter`]: crate::trace::SpanExporter
100#[derive(Debug, Default)]
101pub struct NoopSpanExporter {
102    _private: (),
103}
104
105impl NoopSpanExporter {
106    /// Create a new noop span exporter
107    pub fn new() -> Self {
108        NoopSpanExporter { _private: () }
109    }
110}
111
112impl SpanExporter for NoopSpanExporter {
113    async fn export(&self, _: Vec<SpanData>) -> OTelSdkResult {
114        Ok(())
115    }
116}