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