opentelemetry_spanprocessor_any/sdk/export/trace/
stdout.rs

1//! # Stdout Span Exporter
2//!
3//! The stdout [`SpanExporter`] writes debug printed [`Span`]s to its configured
4//! [`Write`] instance. By default it will write to [`Stdout`].
5//!
6//! [`SpanExporter`]: super::SpanExporter
7//! [`Span`]: crate::trace::Span
8//! [`Write`]: std::io::Write
9//! [`Stdout`]: std::io::Stdout
10//!
11//! # Examples
12//!
13//! ```no_run
14//! use opentelemetry::trace::Tracer;
15//! use opentelemetry::sdk::export::trace::stdout;
16//! use opentelemetry::global::shutdown_tracer_provider;
17//!
18//! fn main() {
19//!     let tracer = stdout::new_pipeline()
20//!         .with_pretty_print(true)
21//!         .install_simple();
22//!
23//!     tracer.in_span("doing_work", |cx| {
24//!         // Traced app logic here...
25//!     });
26//!
27//!     shutdown_tracer_provider(); // sending remaining spans
28//! }
29//! ```
30use crate::{
31    global, sdk,
32    sdk::export::{
33        trace::{ExportResult, SpanData, SpanExporter},
34        ExportError,
35    },
36    trace::TracerProvider,
37};
38use async_trait::async_trait;
39use std::fmt::Debug;
40use std::io::{stdout, Stdout, Write};
41
42/// Pipeline builder
43#[derive(Debug)]
44pub struct PipelineBuilder<W: Write> {
45    pretty_print: bool,
46    trace_config: Option<sdk::trace::Config>,
47    writer: W,
48}
49
50/// Create a new stdout exporter pipeline builder.
51pub fn new_pipeline() -> PipelineBuilder<Stdout> {
52    PipelineBuilder::default()
53}
54
55impl Default for PipelineBuilder<Stdout> {
56    /// Return the default pipeline builder.
57    fn default() -> Self {
58        Self {
59            pretty_print: false,
60            trace_config: None,
61            writer: stdout(),
62        }
63    }
64}
65
66impl<W: Write> PipelineBuilder<W> {
67    /// Specify the pretty print setting.
68    pub fn with_pretty_print(mut self, pretty_print: bool) -> Self {
69        self.pretty_print = pretty_print;
70        self
71    }
72
73    /// Assign the SDK trace configuration.
74    pub fn with_trace_config(mut self, config: sdk::trace::Config) -> Self {
75        self.trace_config = Some(config);
76        self
77    }
78
79    /// Specify the writer to use.
80    pub fn with_writer<T: Write>(self, writer: T) -> PipelineBuilder<T> {
81        PipelineBuilder {
82            pretty_print: self.pretty_print,
83            trace_config: self.trace_config,
84            writer,
85        }
86    }
87}
88
89impl<W> PipelineBuilder<W>
90where
91    W: Write + Debug + Send + 'static,
92{
93    /// Install the stdout exporter pipeline with the recommended defaults.
94    pub fn install_simple(mut self) -> sdk::trace::Tracer {
95        let exporter = Exporter::new(self.writer, self.pretty_print);
96
97        let mut provider_builder =
98            sdk::trace::TracerProvider::builder().with_simple_exporter(exporter);
99        if let Some(config) = self.trace_config.take() {
100            provider_builder = provider_builder.with_config(config);
101        }
102        let provider = provider_builder.build();
103
104        let tracer =
105            provider.versioned_tracer("opentelemetry", Some(env!("CARGO_PKG_VERSION")), None);
106        let _ = global::set_tracer_provider(provider);
107
108        tracer
109    }
110}
111
112/// A [`SpanExporter`] that writes to [`Stdout`] or other configured [`Write`].
113///
114/// [`SpanExporter`]: super::SpanExporter
115/// [`Write`]: std::io::Write
116/// [`Stdout`]: std::io::Stdout
117#[derive(Debug)]
118pub struct Exporter<W: Write> {
119    writer: W,
120    pretty_print: bool,
121}
122
123impl<W: Write> Exporter<W> {
124    /// Create a new stdout `Exporter`.
125    pub fn new(writer: W, pretty_print: bool) -> Self {
126        Self {
127            writer,
128            pretty_print,
129        }
130    }
131}
132
133#[async_trait]
134impl<W> SpanExporter for Exporter<W>
135where
136    W: Write + Debug + Send + 'static,
137{
138    /// Export spans to stdout
139    async fn export(&mut self, batch: Vec<SpanData>) -> ExportResult {
140        for span in batch {
141            if self.pretty_print {
142                self.writer
143                    .write_all(format!("{:#?}\n", span).as_bytes())
144                    .map_err::<Error, _>(Into::into)?;
145            } else {
146                self.writer
147                    .write_all(format!("{:?}\n", span).as_bytes())
148                    .map_err::<Error, _>(Into::into)?;
149            }
150        }
151
152        Ok(())
153    }
154}
155
156/// Stdout exporter's error
157#[derive(thiserror::Error, Debug)]
158#[error(transparent)]
159struct Error(#[from] std::io::Error);
160
161impl ExportError for Error {
162    fn exporter_name(&self) -> &'static str {
163        "stdout"
164    }
165}