From 283cdfa0b234876edf62b30c9b2a408e32f97e4a Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Fri, 3 May 2024 21:22:12 -0700 Subject: [PATCH] wip: parse and propagate log level --- core/lib/Cargo.toml | 2 +- core/lib/src/config/config.rs | 12 +++++---- core/lib/src/rocket.rs | 3 ++- core/lib/src/trace/level.rs | 44 ++++++++++++++++++++++++++++++++ core/lib/src/trace/mod.rs | 26 ++++++++++++------- core/lib/src/trace/subscriber.rs | 29 ++++++++++++--------- 6 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 core/lib/src/trace/level.rs diff --git a/core/lib/Cargo.toml b/core/lib/Cargo.toml index f562667ed0..5e7df91b80 100644 --- a/core/lib/Cargo.toml +++ b/core/lib/Cargo.toml @@ -85,7 +85,7 @@ futures = { version = "0.3.30", default-features = false, features = ["std"] } state = "0.6" # tracing -tracing = { version = "0.1.40", default-features = false, features = ["std"] } +tracing = { version = "0.1.40", default-features = false, features = ["std", "attributes"] } # tracing-futures = { version = "0.2", default-features = false, features = ["std-future"] } [dependencies.tracing-subscriber] diff --git a/core/lib/src/config/config.rs b/core/lib/src/config/config.rs index b22bddde1e..899de41759 100644 --- a/core/lib/src/config/config.rs +++ b/core/lib/src/config/config.rs @@ -3,6 +3,7 @@ use figment::providers::{Serialized, Env, Toml, Format}; use figment::value::{Map, Dict, magic::RelativePathBuf}; use serde::{Deserialize, Serialize}; use yansi::{Paint, Style, Color::Primary}; +use tracing::{level_filters::LevelFilter, Level}; // use crate::log::PaintExt; // use crate::config::{LogLevel, ShutdownConfig, Ident, CliColors}; @@ -123,8 +124,9 @@ pub struct Config { pub secret_key: SecretKey, /// Graceful shutdown configuration. **(default: [`ShutdownConfig::default()`])** pub shutdown: ShutdownConfig, - // /// Max level to log. **(default: _debug_ `normal` / _release_ `critical`)** - // pub log_level: LogLevel, + /// Max level to log. **(default: _debug_ `info` / _release_ `error`)** + #[serde(with = "crate::trace::level")] + pub log_level: Option, /// Whether to use colors and emoji when logging. **(default: /// [`CliColors::Auto`])** pub cli_colors: CliColors, @@ -202,7 +204,7 @@ impl Config { #[cfg(feature = "secrets")] secret_key: SecretKey::zero(), shutdown: ShutdownConfig::default(), - // log_level: LogLevel::Normal, + log_level: Some(Level::INFO), cli_colors: CliColors::Auto, __non_exhaustive: (), } @@ -226,7 +228,7 @@ impl Config { pub fn release_default() -> Config { Config { profile: Self::RELEASE_PROFILE, - // log_level: LogLevel::Critical, + log_level: Some(Level::ERROR), ..Config::debug_default() } } @@ -374,7 +376,7 @@ impl Config { } launch_meta_!("shutdown: {}", self.shutdown.paint(VAL)); - // launch_meta_!("log level: {}", self.log_level.paint(VAL)); + launch_meta_!("log level: {}", LevelFilter::from(self.log_level).paint(VAL)); launch_meta_!("cli colors: {}", self.cli_colors.paint(VAL)); // Check for now deprecated config values. diff --git a/core/lib/src/rocket.rs b/core/lib/src/rocket.rs index 5140c8237a..40d6480fcd 100644 --- a/core/lib/src/rocket.rs +++ b/core/lib/src/rocket.rs @@ -187,7 +187,7 @@ impl Rocket { pub fn custom(provider: T) -> Self { // We initialize the logger here so that logging from fairings and so on // are visible; we use the final config to set a max log-level in ignite - crate::trace::init(&Config::debug_default()); + crate::trace::init(None); let rocket: Rocket = Rocket(Building { figment: Figment::from(provider), @@ -534,6 +534,7 @@ impl Rocket { /// Ok(()) /// } /// ``` + #[tracing::instrument(target = "rocket", skip_all)] pub async fn ignite(mut self) -> Result, Error> { self = Fairings::handle_ignite(self).await; self.fairings.audit().map_err(|f| ErrorKind::FailedFairings(f.to_vec()))?; diff --git a/core/lib/src/trace/level.rs b/core/lib/src/trace/level.rs new file mode 100644 index 0000000000..8755635a98 --- /dev/null +++ b/core/lib/src/trace/level.rs @@ -0,0 +1,44 @@ +use std::fmt; + +use serde::{de, Serialize, Deserializer, Serializer}; +use tracing::{level_filters::LevelFilter, Level}; + +pub fn serialize(level: &Option, s: S) -> Result { + LevelFilter::from(*level).to_string().serialize(s) +} + +pub fn deserialize<'de, D: Deserializer<'de>>(de: D) -> Result, D::Error> { + struct Visitor; + + const E: &str = r#"one of "off", "error", "warn", "info", "debug", "trace", or a number 0-5"#; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = Option; + + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "expected {E}") + } + + fn visit_u64(self, v: u64) -> Result { + let filter = match v { + 0 => LevelFilter::OFF, + 1 => LevelFilter::ERROR, + 2 => LevelFilter::WARN, + 3 => LevelFilter::INFO, + 4 => LevelFilter::DEBUG, + 5 => LevelFilter::TRACE, + _ => return Err(E::invalid_value(de::Unexpected::Unsigned(v), &E)), + }; + + Ok(filter.into_level()) + } + + fn visit_str(self, v: &str) -> Result { + v.parse::() + .map(|f| f.into_level()) + .map_err(|_| E::invalid_value(de::Unexpected::Str(v), &E)) + } + } + + de.deserialize_map(Visitor) +} diff --git a/core/lib/src/trace/mod.rs b/core/lib/src/trace/mod.rs index 9703ce480f..ac64388236 100644 --- a/core/lib/src/trace/mod.rs +++ b/core/lib/src/trace/mod.rs @@ -2,6 +2,7 @@ use rocket::Config; #[cfg(feature = "trace")] pub mod subscriber; +pub mod level; pub trait PaintExt: Sized { fn emoji(self) -> yansi::Painted; @@ -16,27 +17,34 @@ impl PaintExt for &str { } macro_rules! declare_macro { - ($($name:ident),*) => ( - $(declare_macro!([$] $name);)* + ($($name:ident $level:ident),* $(,)?) => ( + $(declare_macro!([$] $name $level);)* ); - ([$d:tt] $name:ident) => ( + ([$d:tt] $name:ident $level:ident) => ( #[macro_export] macro_rules! $name { ($d ($t:tt)*) => ({ #[allow(unused_imports)] use $crate::trace::PaintExt as _; - $crate::tracing::event!($crate::tracing::Level::INFO, $d ($t)*); + $crate::tracing::event!($crate::tracing::Level::$level, $d ($t)*); }) } ); } -declare_macro!(log, log_, launch_info, launch_info_, launch_meta, launch_meta_, - error, error_, info, info_, trace, trace_, debug, debug_, warn, warn_); - -pub fn init(_config: &Config) { +declare_macro!( + launch_info INFO, launch_info_ INFO, + launch_meta INFO, launch_meta_ INFO, + error ERROR, error_ ERROR, + info INFO, info_ INFO, + trace TRACE, trace_ TRACE, + debug DEBUG, debug_ DEBUG, + warn WARN, warn_ WARN, +); + +pub fn init<'a, T: Into>>(_config: T) { #[cfg(feature = "trace")] - subscriber::init(_config); + subscriber::init(_config.into()); } diff --git a/core/lib/src/trace/subscriber.rs b/core/lib/src/trace/subscriber.rs index a115c3dc8b..a1973937b4 100644 --- a/core/lib/src/trace/subscriber.rs +++ b/core/lib/src/trace/subscriber.rs @@ -7,6 +7,7 @@ use tracing_subscriber::registry::LookupSpan; use tracing_subscriber::{reload, filter, Layer, Registry}; use yansi::{Condition, Paint, Painted}; +use crate::config::CliColors; use crate::Config; pub trait PaintExt: Sized { @@ -21,9 +22,9 @@ impl PaintExt for &str { } } -pub fn filter_layer(level: Level) -> filter::Targets { +pub fn filter_layer(level: impl Into) -> filter::Targets { filter::Targets::new() - .with_default(level) + .with_default(level.into()) .with_target("rustls", LevelFilter::OFF) .with_target("hyper", LevelFilter::OFF) } @@ -35,20 +36,24 @@ pub fn fmt_layer LookupSpan<'span>>() -> impl Layer) { static HANDLE: OnceLock> = OnceLock::new(); - // FIXME: Read the true level from `config`. - let level = Level::INFO; + // Do nothing if there's no config and we've already initialized. + if config.is_none() && HANDLE.get().is_some() { + return; + } // Always disable colors if requested or if the stdout/err aren't TTYs. - let should_color = match config.cli_colors { - crate::config::CliColors::Always => Condition::ALWAYS, - crate::config::CliColors::Auto => Condition::DEFAULT, - crate::config::CliColors::Never => Condition::NEVER, + let cli_colors = config.map(|c| c.cli_colors).unwrap_or(CliColors::Auto); + let should_color = match cli_colors { + CliColors::Always => Condition::ALWAYS, + CliColors::Auto => Condition::DEFAULT, + CliColors::Never => Condition::NEVER, }; - let (filter, reload_handle) = reload::Layer::new(filter_layer(level)); + let log_level = config.map(|c| c.log_level).unwrap_or(Some(Level::INFO)); + let (filter, reload_handle) = reload::Layer::new(filter_layer(log_level)); let result = tracing_subscriber::registry() .with(filter) .with(fmt_layer()) @@ -57,8 +62,8 @@ pub(crate) fn init(config: &Config) { if result.is_ok() { assert!(HANDLE.set(reload_handle).is_ok()); yansi::whenever(should_color); - } else if let Some(handle) = HANDLE.get() { - assert!(handle.modify(|filter| *filter = filter_layer(level)).is_ok()); + } if let Some(handle) = HANDLE.get() { + assert!(handle.modify(|filter| *filter = filter_layer(log_level)).is_ok()); yansi::whenever(should_color); } else { yansi::disable()