pub(crate) mod metrics;
pub(crate) mod observer;
use anyhow::Context;
use opentelemetry::trace::TracerProvider as _;
use opentelemetry_otlp::SpanExporter;
use opentelemetry_sdk::Resource;
use opentelemetry_sdk::trace::SdkTracerProvider;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{EnvFilter, Layer, Registry};
pub(crate) fn init_tracing() -> Option<SdkTracerProvider> {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
let json = std::env::var("FLUSSO_LOG_FORMAT")
.map(|value| value.eq_ignore_ascii_case("json"))
.unwrap_or(false);
let fmt_layer: Box<dyn Layer<Registry> + Send + Sync> = if json {
Box::new(
tracing_subscriber::fmt::layer()
.json()
.with_writer(std::io::stderr),
)
} else {
Box::new(tracing_subscriber::fmt::layer().with_writer(std::io::stderr))
};
let mut layers: Vec<Box<dyn Layer<Registry> + Send + Sync>> = vec![fmt_layer];
let mut otlp_error: Option<String> = None;
let provider = match otlp_provider() {
Ok(Some(provider)) => {
let tracer = provider.tracer("flusso");
layers.push(Box::new(tracing_opentelemetry::layer().with_tracer(tracer)));
Some(provider)
}
Ok(None) => None,
Err(error) => {
otlp_error = Some(format!("{error:#}"));
None
}
};
Registry::default().with(layers).with(filter).init();
if let Some(error) = otlp_error {
tracing::warn!(error, "OTLP trace export disabled; logging to stderr only");
} else if provider.is_some() {
tracing::info!("OTLP trace export enabled");
}
provider
}
fn otlp_provider() -> anyhow::Result<Option<SdkTracerProvider>> {
let configured = std::env::var_os("OTEL_EXPORTER_OTLP_ENDPOINT").is_some()
|| std::env::var_os("OTEL_EXPORTER_OTLP_TRACES_ENDPOINT").is_some();
if !configured {
return Ok(None);
}
let exporter = SpanExporter::builder()
.with_http()
.build()
.context("building OTLP span exporter")?;
let resource = Resource::builder()
.with_service_name(env!("CARGO_PKG_NAME"))
.build();
let provider = SdkTracerProvider::builder()
.with_batch_exporter(exporter)
.with_resource(resource)
.build();
Ok(Some(provider))
}