use std::fmt::Debug;
use futures_core::future::BoxFuture;
use opentelemetry::{
global,
trace::{TraceError, TracerProvider},
};
use opentelemetry_sdk::{
self as sdk,
export::trace::{ExportResult, SpanData},
};
use opentelemetry_semantic_conventions::SCHEMA_URL;
use sdk::runtime::RuntimeChannel;
#[cfg(feature = "grpc-tonic")]
use crate::exporter::tonic::TonicExporterBuilder;
#[cfg(feature = "grpc-sys")]
use crate::exporter::grpcio::GrpcioExporterBuilder;
#[cfg(feature = "http-proto")]
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::Tracer, 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::Tracer, 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::Tracer {
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);
}
let provider = provider_builder.build();
let tracer = provider.versioned_tracer(
"opentelemetry-otlp",
Some(env!("CARGO_PKG_VERSION")),
Some(SCHEMA_URL),
None,
);
let _ = global::set_tracer_provider(provider);
tracer
}
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::Tracer {
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);
}
let provider = provider_builder.build();
let tracer = provider.versioned_tracer(
"opentelemetry-otlp",
Some(env!("CARGO_PKG_VERSION")),
Some(SCHEMA_URL),
None,
);
let _ = global::set_tracer_provider(provider);
tracer
}
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
#[non_exhaustive]
pub enum SpanExporterBuilder {
#[cfg(feature = "grpc-tonic")]
Tonic(TonicExporterBuilder),
#[cfg(feature = "grpc-sys")]
Grpcio(GrpcioExporterBuilder),
#[cfg(feature = "http-proto")]
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(feature = "grpc-sys")]
SpanExporterBuilder::Grpcio(builder) => builder.build_span_exporter(),
#[cfg(feature = "http-proto")]
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(feature = "grpc-sys")]
impl From<GrpcioExporterBuilder> for SpanExporterBuilder {
fn from(exporter: GrpcioExporterBuilder) -> Self {
SpanExporterBuilder::Grpcio(exporter)
}
}
#[cfg(feature = "http-proto")]
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)
}
}