use std::fmt::Debug;
use futures_core::future::BoxFuture;
use opentelemetry::trace::TraceError;
use opentelemetry_sdk::{
self as sdk,
export::trace::{ExportResult, SpanData},
};
use sdk::runtime::RuntimeChannel;
#[cfg(feature = "grpc-tonic")]
use crate::exporter::tonic::TonicExporterBuilder;
#[cfg(any(feature = "http-proto", feature = "http-json"))]
use crate::exporter::http::HttpExporterBuilder;
use crate::{NoExporterConfig, OtlpPipeline};
pub const OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: &str = "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT";
pub const OTEL_EXPORTER_OTLP_TRACES_TIMEOUT: &str = "OTEL_EXPORTER_OTLP_TRACES_TIMEOUT";
pub const OTEL_EXPORTER_OTLP_TRACES_COMPRESSION: &str = "OTEL_EXPORTER_OTLP_TRACES_COMPRESSION";
pub const OTEL_EXPORTER_OTLP_TRACES_HEADERS: &str = "OTEL_EXPORTER_OTLP_TRACES_HEADERS";
impl OtlpPipeline {
pub fn tracing(self) -> OtlpTracePipeline<NoExporterConfig> {
OtlpTracePipeline {
exporter_builder: NoExporterConfig(()),
trace_config: None,
batch_config: None,
}
}
}
#[derive(Debug)]
pub struct OtlpTracePipeline<EB> {
exporter_builder: EB,
trace_config: Option<sdk::trace::Config>,
batch_config: Option<sdk::trace::BatchConfig>,
}
impl<EB> OtlpTracePipeline<EB> {
pub fn with_trace_config(mut self, trace_config: sdk::trace::Config) -> Self {
self.trace_config = Some(trace_config);
self
}
pub fn with_batch_config(mut self, batch_config: sdk::trace::BatchConfig) -> Self {
self.batch_config = Some(batch_config);
self
}
}
impl OtlpTracePipeline<NoExporterConfig> {
pub fn with_exporter<B: Into<SpanExporterBuilder>>(
self,
pipeline: B,
) -> OtlpTracePipeline<SpanExporterBuilder> {
OtlpTracePipeline {
exporter_builder: pipeline.into(),
trace_config: self.trace_config,
batch_config: self.batch_config,
}
}
}
impl OtlpTracePipeline<SpanExporterBuilder> {
pub fn install_simple(self) -> Result<sdk::trace::TracerProvider, TraceError> {
Ok(build_simple_with_exporter(
self.exporter_builder.build_span_exporter()?,
self.trace_config,
))
}
pub fn install_batch<R: RuntimeChannel>(
self,
runtime: R,
) -> Result<sdk::trace::TracerProvider, TraceError> {
Ok(build_batch_with_exporter(
self.exporter_builder.build_span_exporter()?,
self.trace_config,
runtime,
self.batch_config,
))
}
}
fn build_simple_with_exporter(
exporter: SpanExporter,
trace_config: Option<sdk::trace::Config>,
) -> sdk::trace::TracerProvider {
let mut provider_builder = sdk::trace::TracerProvider::builder().with_simple_exporter(exporter);
if let Some(config) = trace_config {
provider_builder = provider_builder.with_config(config);
}
provider_builder.build()
}
fn build_batch_with_exporter<R: RuntimeChannel>(
exporter: SpanExporter,
trace_config: Option<sdk::trace::Config>,
runtime: R,
batch_config: Option<sdk::trace::BatchConfig>,
) -> sdk::trace::TracerProvider {
let mut provider_builder = sdk::trace::TracerProvider::builder();
let batch_processor = sdk::trace::BatchSpanProcessor::builder(exporter, runtime)
.with_batch_config(batch_config.unwrap_or_default())
.build();
provider_builder = provider_builder.with_span_processor(batch_processor);
if let Some(config) = trace_config {
provider_builder = provider_builder.with_config(config);
}
provider_builder.build()
}
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
#[non_exhaustive]
pub enum SpanExporterBuilder {
#[cfg(feature = "grpc-tonic")]
Tonic(TonicExporterBuilder),
#[cfg(any(feature = "http-proto", feature = "http-json"))]
Http(HttpExporterBuilder),
}
impl SpanExporterBuilder {
pub fn build_span_exporter(self) -> Result<SpanExporter, TraceError> {
match self {
#[cfg(feature = "grpc-tonic")]
SpanExporterBuilder::Tonic(builder) => builder.build_span_exporter(),
#[cfg(any(feature = "http-proto", feature = "http-json"))]
SpanExporterBuilder::Http(builder) => builder.build_span_exporter(),
}
}
}
#[cfg(feature = "grpc-tonic")]
impl From<TonicExporterBuilder> for SpanExporterBuilder {
fn from(exporter: TonicExporterBuilder) -> Self {
SpanExporterBuilder::Tonic(exporter)
}
}
#[cfg(any(feature = "http-proto", feature = "http-json"))]
impl From<HttpExporterBuilder> for SpanExporterBuilder {
fn from(exporter: HttpExporterBuilder) -> Self {
SpanExporterBuilder::Http(exporter)
}
}
#[derive(Debug)]
pub struct SpanExporter(Box<dyn opentelemetry_sdk::export::trace::SpanExporter>);
impl SpanExporter {
pub fn new(client: impl opentelemetry_sdk::export::trace::SpanExporter + 'static) -> Self {
SpanExporter(Box::new(client))
}
}
impl opentelemetry_sdk::export::trace::SpanExporter for SpanExporter {
fn export(&mut self, batch: Vec<SpanData>) -> BoxFuture<'static, ExportResult> {
self.0.export(batch)
}
fn set_resource(&mut self, resource: &opentelemetry_sdk::Resource) {
self.0.set_resource(resource);
}
}