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};
#[derive(Debug)]
pub struct PipelineBuilder<W: Write> {
pretty_print: bool,
trace_config: Option<sdk::trace::Config>,
writer: W,
}
pub fn new_pipeline() -> PipelineBuilder<Stdout> {
PipelineBuilder::default()
}
impl Default for PipelineBuilder<Stdout> {
fn default() -> Self {
Self {
pretty_print: false,
trace_config: None,
writer: stdout(),
}
}
}
impl<W: Write> PipelineBuilder<W> {
pub fn with_pretty_print(mut self, pretty_print: bool) -> Self {
self.pretty_print = pretty_print;
self
}
pub fn with_trace_config(mut self, config: sdk::trace::Config) -> Self {
self.trace_config = Some(config);
self
}
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,
{
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
}
}
#[derive(Debug)]
pub struct Exporter<W: Write> {
writer: W,
pretty_print: bool,
}
impl<W: Write> Exporter<W> {
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,
{
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(())
}
}
#[derive(thiserror::Error, Debug)]
#[error(transparent)]
struct Error(#[from] std::io::Error);
impl ExportError for Error {
fn exporter_name(&self) -> &'static str {
"stdout"
}
}