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 }