use std::sync::OnceLock;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{EnvFilter, Layer, Registry, reload};
type OtelSlot = Option<leviath_telemetry::LogLayer>;
static OTEL_HANDLE: OnceLock<reload::Handle<OtelSlot, Registry>> = OnceLock::new();
pub fn init(verbose: bool) {
let level = if verbose { "debug" } else { "info" };
let (otel_layer, handle) = reload::Layer::new(None as OtelSlot);
let subscriber = tracing_subscriber::registry().with(otel_layer).with(
tracing_subscriber::fmt::layer()
.with_writer(std::io::stderr)
.with_filter(EnvFilter::new(level)),
);
let _ = subscriber.try_init();
let _ = OTEL_HANDLE.set(handle);
}
pub fn install_otel_layer(layer: leviath_telemetry::LogLayer) -> bool {
match OTEL_HANDLE.get() {
Some(handle) => handle.reload(Some(layer)).is_ok(),
None => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
use opentelemetry_sdk::logs::{InMemoryLogExporter, SdkLoggerProvider};
fn bridge_with_exporter() -> (leviath_telemetry::LogLayer, InMemoryLogExporter) {
let exporter = InMemoryLogExporter::default();
let provider = SdkLoggerProvider::builder()
.with_simple_exporter(exporter.clone())
.build();
let sink = leviath_telemetry::OtelSink::new(
opentelemetry_sdk::trace::SdkTracerProvider::builder().build(),
opentelemetry_sdk::metrics::SdkMeterProvider::builder().build(),
provider,
);
(sink.tracing_log_layer(), exporter)
}
#[test]
fn init_parks_the_handle_and_install_forwards_events() {
let (layer, _exporter) = bridge_with_exporter();
assert!(!install_otel_layer(layer));
let (otel_layer, handle) = reload::Layer::new(None as OtelSlot);
assert!(
OTEL_HANDLE.set(handle).is_ok(),
"this test parks the handle first"
);
let subscriber = tracing_subscriber::registry().with(otel_layer);
let _guard = tracing::subscriber::set_default(subscriber);
let (layer, exporter) = bridge_with_exporter();
assert!(install_otel_layer(layer));
tracing::info!(target: "leviath::logging::test", "forwarded line");
let emitted = exporter.get_emitted_logs().unwrap();
assert!(
emitted
.iter()
.any(|log| format!("{:?}", log.record.body()).contains("forwarded line")),
"{emitted:?}"
);
tracing::info!(target: "opentelemetry_sdk", "feedback line");
let emitted = exporter.get_emitted_logs().unwrap();
assert!(
!emitted
.iter()
.any(|log| format!("{:?}", log.record.body()).contains("feedback line"))
);
init(false);
init(true);
let (layer, _exporter) = bridge_with_exporter();
assert!(install_otel_layer(layer));
}
}