use tracing_subscriber::{
EnvFilter, Layer as _, Registry, filter::Filtered, fmt as tracing_fmt, layer::SubscriberExt,
reload as tracing_reload, util::SubscriberInitExt,
};
pub trait ProvidesEnvFilter {
fn log_filter(&self) -> EnvFilter;
}
pub type FilteredFmtLayer = Filtered<tracing_fmt::Layer<Registry>, EnvFilter, Registry>;
pub type ReloadableFilteredFmtLayer = tracing_reload::Layer<FilteredFmtLayer, Registry>;
pub type ReloadableFilteredFmtLayerHandle = tracing_reload::Handle<FilteredFmtLayer, Registry>;
pub fn setup_reloadable_fmt_layer(
initial_filter: EnvFilter,
) -> (ReloadableFilteredFmtLayer, ReloadableFilteredFmtLayerHandle) {
let fmt_layer: FilteredFmtLayer = tracing_fmt::Layer::default().with_filter(initial_filter);
ReloadableFilteredFmtLayer::new(fmt_layer)
}
pub type FilteredJournalDLayer = Filtered<tracing_journald::Layer, EnvFilter, Registry>;
pub type ReloadableFilteredJournalDLayer = tracing_reload::Layer<FilteredJournalDLayer, Registry>;
pub type ReloadableFilteredJournalDLayerHandle = tracing_reload::Handle<FilteredJournalDLayer, Registry>;
pub fn setup_reloadable_journald_layer(
initial_filter: EnvFilter,
) -> Result<(ReloadableFilteredJournalDLayer, ReloadableFilteredJournalDLayerHandle), std::io::Error> {
let journald_layer: FilteredJournalDLayer = tracing_journald::Layer::new()?.with_filter(initial_filter);
Ok(ReloadableFilteredJournalDLayer::new(journald_layer))
}
pub enum ReloadableLocalLogHandle {
Fmt(ReloadableFilteredFmtLayerHandle),
JournalD(ReloadableFilteredJournalDLayerHandle),
}
impl ReloadableLocalLogHandle {
pub fn replace_filter(&self, new_filter: EnvFilter) {
match self {
Self::Fmt(handle) => {
let _ = handle.modify(|layer| *layer.filter_mut() = new_filter);
},
Self::JournalD(handle) => {
let _ = handle.modify(|layer| *layer.filter_mut() = new_filter);
},
}
}
}
pub fn setup_local_logging(initial_filter: EnvFilter, try_journald: bool) -> ReloadableLocalLogHandle {
let mut journald_error = None;
if try_journald {
match setup_reloadable_journald_layer(initial_filter.clone()) {
Ok((layer, handle)) => {
tracing_subscriber::registry().with(layer).init();
return ReloadableLocalLogHandle::JournalD(handle);
},
Err(err) => journald_error = Some(err),
}
}
let (layer, handle) = setup_reloadable_fmt_layer(initial_filter);
tracing_subscriber::registry().with(layer).init();
if let Some(journald_error) = journald_error {
tracing::error!("failed to connect to journald: {journald_error}");
}
ReloadableLocalLogHandle::Fmt(handle)
}
#[cfg(test)]
#[path = "../tests/app/log.rs"]
mod tests;