jannie

jannie (mirror)
Log | Files | Refs | README | LICENSE

logging.rs (2946B)


      1 use tracing::Level;
      2 use tracing_subscriber::{
      3     Layer,
      4     fmt::writer::BoxMakeWriter,
      5     layer::{Filter, SubscriberExt},
      6     util::SubscriberInitExt,
      7 };
      8 
      9 use crate::config::logging::{LogFormat, LoggingConfig, SubscriberConfig, TargetFilterType};
     10 
     11 /// Sets up a log implementation that logs to stdout.
     12 pub fn setup_logging(config: &LoggingConfig) -> Result<(), Error> {
     13     let file_layer = config.file.as_ref().map(|config| {
     14         let writer = BoxMakeWriter::new(tracing_appender::rolling::RollingFileAppender::new(
     15             tracing_appender::rolling::Rotation::NEVER,
     16             &config.directory,
     17             &config.prefix,
     18         ));
     19         fmt_subscriber(writer, &config.subscriber)
     20     });
     21     let mut subscribers = Vec::new();
     22     if let Some(file_layer) = file_layer {
     23         subscribers.push(file_layer.boxed());
     24     }
     25     tracing_subscriber::registry()
     26         .with(subscribers)
     27         .try_init()
     28         .map_err(|error| Error::TracingSubscriber(error.to_string()))?;
     29     Ok(())
     30 }
     31 
     32 fn fmt_subscriber<S: tracing::Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>>(
     33     writer: BoxMakeWriter,
     34     config: &SubscriberConfig,
     35 ) -> Option<impl Layer<S> + 'static> {
     36     let fmt = tracing_subscriber::fmt::layer()
     37         .with_writer(writer)
     38         .with_ansi(config.ansi)
     39         .with_target(config.target)
     40         .with_file(config.file_path)
     41         .with_line_number(config.line_number);
     42     let fmt = match config.format {
     43         LogFormat::Plain => fmt.boxed(),
     44         LogFormat::Json => fmt.json().boxed(),
     45     };
     46     let fmt = fmt
     47         .with_filter(tracing_subscriber::filter::LevelFilter::from_level(
     48             Option::<Level>::from(config.level)?,
     49         ))
     50         .with_filter(subscriber_target_filter(config));
     51     Some(fmt.boxed())
     52 }
     53 
     54 fn subscriber_target_filter<S: tracing::Subscriber>(
     55     config: &SubscriberConfig,
     56 ) -> impl Filter<S> + 'static {
     57     let whitelist_filters = config
     58         .target_filters
     59         .clone()
     60         .into_iter()
     61         .filter(|filter| matches!(filter.filter_type, TargetFilterType::Whitelist))
     62         .collect::<Vec<_>>();
     63     let blacklist_filters = config
     64         .target_filters
     65         .clone()
     66         .into_iter()
     67         .filter(|filter| matches!(filter.filter_type, TargetFilterType::Blacklist))
     68         .collect::<Vec<_>>();
     69     tracing_subscriber::filter::FilterFn::new(move |log| {
     70         let whitelisted = whitelist_filters.is_empty()
     71             || whitelist_filters
     72                 .iter()
     73                 .any(|filter| log.target().contains(&filter.pattern));
     74         let blacklisted = !blacklist_filters.is_empty()
     75             && blacklist_filters
     76                 .iter()
     77                 .any(|filter| log.target().contains(&filter.pattern));
     78         whitelisted && !blacklisted
     79     })
     80 }
     81 
     82 #[derive(thiserror::Error, Debug)]
     83 pub enum Error {
     84     #[error("Error setting global subscriber: {0}")]
     85     TracingSubscriber(String),
     86 }