lxy 0.1.1

A convenient async http and RPC framework in Rust
Documentation
//! Builder for OpenTelemetry tracing integration.

use opentelemetry::trace::TracerProvider;
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::trace::{
  BatchSpanProcessor, Sampler, SdkTracerProvider, SimpleSpanProcessor,
};

use super::config::{ExporterProtocol, OtelConfig, SpanProcessorType};

/// Initializes the OpenTelemetry tracer provider based on configuration.
pub fn init_tracer_provider(config: &OtelConfig) -> SdkTracerProvider {
  let exporter = create_exporter(config);

  match config.processor {
    SpanProcessorType::Simple => {
      let processor = SimpleSpanProcessor::new(exporter);
      SdkTracerProvider::builder()
        .with_sampler(Sampler::AlwaysOn)
        .with_span_processor(processor)
        .with_resource(
          opentelemetry_sdk::Resource::builder()
            .with_service_name(config.service_name.clone())
            .build(),
        )
        .build()
    }
    SpanProcessorType::Batch => {
      let processor = BatchSpanProcessor::builder(exporter).build();
      SdkTracerProvider::builder()
        .with_sampler(Sampler::AlwaysOn)
        .with_span_processor(processor)
        .with_resource(
          opentelemetry_sdk::Resource::builder()
            .with_service_name(config.service_name.clone())
            .build(),
        )
        .build()
    }
  }
}

/// Creates an OTLP exporter based on the protocol configuration.
fn create_exporter(config: &OtelConfig) -> opentelemetry_otlp::SpanExporter {
  match config.protocol {
    ExporterProtocol::Grpc => opentelemetry_otlp::SpanExporter::builder()
      .with_tonic()
      .with_endpoint(config.endpoint.clone())
      .build()
      .unwrap_or_else(|e| {
        panic!(
          "Failed to build OTLP gRPC exporter for endpoint '{}': {}",
          config.endpoint, e
        )
      }),
    ExporterProtocol::Http => opentelemetry_otlp::SpanExporter::builder()
      .with_http()
      .with_endpoint(config.endpoint.clone())
      .build()
      .unwrap_or_else(|e| {
        panic!(
          "Failed to build OTLP HTTP exporter for endpoint '{}': {}",
          config.endpoint, e
        )
      }),
  }
}

/// Creates an OpenTelemetry tracing layer for integration with `tracing-subscriber`.
///
/// This layer bridges the `tracing` ecosystem with OpenTelemetry, allowing spans
/// created via `tracing` macros to be exported to OpenTelemetry-compatible backends.
pub fn create_otel_layer<S>(
  provider: &SdkTracerProvider,
) -> tracing_opentelemetry::OpenTelemetryLayer<S, opentelemetry_sdk::trace::Tracer>
where
  S: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span>,
{
  let tracer = provider.tracer("lxy");
  tracing_opentelemetry::layer().with_tracer(tracer)
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn test_otel_config_defaults() {
    let config = OtelConfig::default();
    assert_eq!(config.service_name, "lxy-service");
    assert_eq!(config.endpoint, "http://localhost:4317");
    assert_eq!(config.protocol, ExporterProtocol::Http);
    assert_eq!(config.processor, SpanProcessorType::Simple);
  }
}