use gethostname::gethostname;
use opentelemetry::KeyValue;
use opentelemetry_otlp::{Protocol, WithExportConfig};
use opentelemetry_sdk::trace::{self, Sampler};
use opentelemetry_sdk::Resource;
use std::time::Duration;
use tracing::Subscriber;
use tracing_subscriber::Registry;
use tracing_subscriber::{prelude::*, EnvFilter};
pub const MAX_EVENTS_PER_SPAN: u32 = 64 * 1024;
pub const MAX_ATTRIBUTES_PER_SPAN: u32 = 128;
pub fn start_logging_pipeline(
otlp_endpoint: &Option<String>,
log_filter: crate::LogLevel,
service_name: &'static str,
) -> Result<Box<dyn Subscriber + Send + Sync>, String> {
let forest_filter: EnvFilter = EnvFilter::builder()
.with_default_directive(log_filter.into())
.from_env_lossy();
match otlp_endpoint {
Some(endpoint) => {
let forest_filter = forest_filter
.add_directive(
"tonic=info"
.parse()
.expect("Failed to set tonic logging to info"),
)
.add_directive("h2=info".parse().expect("Failed to set h2 logging to info"))
.add_directive(
"hyper=info"
.parse()
.expect("Failed to set hyper logging to info"),
);
let forest_layer = tracing_forest::ForestLayer::default().with_filter(forest_filter);
let t_filter: EnvFilter = EnvFilter::builder()
.with_default_directive(log_filter.into())
.from_env_lossy();
let tracer = opentelemetry_otlp::new_pipeline().tracing().with_exporter(
opentelemetry_otlp::new_exporter()
.tonic()
.with_endpoint(endpoint)
.with_timeout(Duration::from_secs(5))
.with_protocol(Protocol::HttpBinary),
);
let git_rev = match option_env!("KANIDM_PKG_COMMIT_REV") {
Some(rev) => format!("-{}", rev),
None => "".to_string(),
};
let version = format!("{}{}", env!("CARGO_PKG_VERSION"), git_rev);
let hostname = gethostname();
let hostname = hostname.to_string_lossy();
let hostname = hostname.to_lowercase();
let tracer = tracer
.with_trace_config(
trace::config()
.with_sampler(Sampler::AlwaysOn)
.with_max_events_per_span(MAX_EVENTS_PER_SPAN)
.with_max_attributes_per_span(MAX_ATTRIBUTES_PER_SPAN)
.with_resource(Resource::new(vec![
KeyValue::new("service.name", service_name),
KeyValue::new("service.version", version),
KeyValue::new("host.name", hostname),
])),
)
.install_batch(opentelemetry::runtime::Tokio)
.map_err(|err| {
let err = format!("Failed to start OTLP pipeline: {:?}", err);
eprintln!("{}", err);
err
})?;
let telemetry = tracing_opentelemetry::layer()
.with_tracer(tracer)
.with_threads(true)
.with_filter(t_filter);
Ok(Box::new(
Registry::default().with(forest_layer).with(telemetry),
))
}
None => {
let forest_layer = tracing_forest::ForestLayer::default().with_filter(forest_filter);
Ok(Box::new(Registry::default().with(forest_layer)))
}
}
}
pub struct TracingPipelineGuard {}
impl Drop for TracingPipelineGuard {
fn drop(&mut self) {
opentelemetry::global::shutdown_tracer_provider();
opentelemetry::global::shutdown_logger_provider();
eprintln!("Logging pipeline completed shutdown");
}
}