use opentelemetry::trace::TraceId;
use tracing_subscriber::{prelude::*, EnvFilter, Registry};
pub fn get_trace_id() -> TraceId {
use opentelemetry::trace::TraceContextExt as _; use tracing_opentelemetry::OpenTelemetrySpanExt as _; tracing::Span::current()
.context()
.span()
.span_context()
.trace_id()
}
#[cfg(feature = "telemetry")]
async fn init_tracer() -> opentelemetry::sdk::trace::Tracer {
let otlp_endpoint =
std::env::var("OPENTELEMETRY_ENDPOINT_URL").expect("Need a otel tracing collector configured");
let channel = tonic::transport::Channel::from_shared(otlp_endpoint)
.unwrap()
.connect()
.await
.unwrap();
opentelemetry_otlp::new_pipeline()
.tracing()
.with_exporter(opentelemetry_otlp::new_exporter().tonic().with_channel(channel))
.with_trace_config(opentelemetry::sdk::trace::config().with_resource(
opentelemetry::sdk::Resource::new(vec![opentelemetry::KeyValue::new(
"service.name",
"tembo-controller",
)]),
))
.install_batch(opentelemetry::runtime::Tokio)
.unwrap()
}
pub async fn init() {
#[cfg(feature = "telemetry")]
let telemetry = tracing_opentelemetry::layer().with_tracer(init_tracer().await);
let logger = tracing_subscriber::fmt::layer()
.compact()
.with_line_number(true)
.with_target(true);
let env_filter = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new("info"))
.unwrap();
#[cfg(feature = "telemetry")]
let collector = Registry::default().with(telemetry).with(logger).with(env_filter);
#[cfg(not(feature = "telemetry"))]
let collector = Registry::default().with(logger).with(env_filter);
tracing::subscriber::set_global_default(collector).unwrap();
}
#[cfg(test)]
mod test {
#[cfg(feature = "telemetry")]
#[tokio::test]
#[ignore = "requires a trace exporter"]
async fn get_trace_id_returns_valid_traces() {
use super::*;
super::init().await;
#[tracing::instrument(name = "test_span")] fn test_trace_id() -> TraceId {
get_trace_id()
}
assert_ne!(test_trace_id(), TraceId::INVALID, "valid trace");
}
}