use crate::observability::config::{OtlpProtocol, TraceConfig};
use crate::observability::filter::SharedOrderedFilter;
use crate::observability::otlp_http::build_no_proxy_http_client;
use crate::observability::remote::{append_otlp_path, resource};
use anyhow::{bail, Context as AnyhowContext, Result};
use opentelemetry::trace::TracerProvider;
use opentelemetry_otlp::{Protocol, SpanExporter, WithExportConfig, WithHttpConfig};
use opentelemetry_sdk::trace::SdkTracerProvider;
use tracing_subscriber::{Layer, Registry};
pub fn build_trace_layer(
config: &TraceConfig,
filter: SharedOrderedFilter,
) -> Result<(Box<dyn Layer<Registry> + Send + Sync>, SdkTracerProvider)> {
if config.exporter != "otlp" {
bail!("unsupported trace exporter `{}`", config.exporter);
}
let exporter = match config.protocol {
OtlpProtocol::HttpBinary => SpanExporter::builder()
.with_http()
.with_http_client(build_no_proxy_http_client()?)
.with_protocol(Protocol::HttpBinary)
.with_endpoint(append_otlp_path(&config.endpoint, "/v1/traces"))
.build(),
OtlpProtocol::Grpc => SpanExporter::builder()
.with_tonic()
.with_endpoint(config.endpoint.clone())
.build(),
}
.context("failed to create OpenTelemetry trace exporter")?;
let provider = SdkTracerProvider::builder()
.with_batch_exporter(exporter)
.with_resource(resource(config))
.build();
let tracer = provider.tracer("pi_logger");
let layer = tracing_opentelemetry::layer()
.with_tracer(tracer)
.with_filter(filter)
.boxed();
Ok((layer, provider))
}