use std::time::Duration;
use anyhow::bail;
use opentelemetry::{global, trace::TracerProvider};
use opentelemetry_otlp::SpanExporterBuilder;
use opentelemetry_sdk::{
resource::{EnvResourceDetector, TelemetryResourceDetector},
Resource,
};
use tracing::Subscriber;
use tracing_subscriber::{registry::LookupSpan, EnvFilter, Layer};
use crate::detector::SpinResourceDetector;
use crate::env::OtlpProtocol;
pub(crate) fn otel_tracing_layer<S: Subscriber + for<'span> LookupSpan<'span>>(
spin_version: String,
) -> anyhow::Result<impl Layer<S>> {
let resource = Resource::from_detectors(
Duration::from_secs(5),
vec![
Box::new(SpinResourceDetector::new(spin_version)),
Box::new(EnvResourceDetector::new()),
Box::new(TelemetryResourceDetector),
],
);
let exporter_builder: SpanExporterBuilder = match OtlpProtocol::traces_protocol_from_env() {
OtlpProtocol::Grpc => opentelemetry_otlp::new_exporter().tonic().into(),
OtlpProtocol::HttpProtobuf => opentelemetry_otlp::new_exporter().http().into(),
OtlpProtocol::HttpJson => bail!("http/json OTLP protocol is not supported"),
};
let tracer_provider = opentelemetry_otlp::new_pipeline()
.tracing()
.with_exporter(exporter_builder)
.with_trace_config(opentelemetry_sdk::trace::Config::default().with_resource(resource))
.install_batch(opentelemetry_sdk::runtime::Tokio)?;
global::set_tracer_provider(tracer_provider.clone());
let env_filter = match EnvFilter::try_from_env("SPIN_OTEL_TRACING_LEVEL") {
Ok(filter) => filter,
Err(_) => EnvFilter::new("info"),
};
Ok(tracing_opentelemetry::layer()
.with_tracer(tracer_provider.tracer("spin"))
.with_threads(false)
.with_filter(env_filter))
}