diff --git a/lib/core/libimagrt/Cargo.toml b/lib/core/libimagrt/Cargo.toml index 63e97ee2..31a04a8e 100644 --- a/lib/core/libimagrt/Cargo.toml +++ b/lib/core/libimagrt/Cargo.toml @@ -29,6 +29,8 @@ toml-query = "0.9" atty = "0.2" failure = "0.1" failure_derive = "0.1" +serde_derive = "1" +serde = "1" libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" } libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" } diff --git a/lib/core/libimagrt/src/lib.rs b/lib/core/libimagrt/src/lib.rs index 825b49e0..4247ff6c 100644 --- a/lib/core/libimagrt/src/lib.rs +++ b/lib/core/libimagrt/src/lib.rs @@ -41,6 +41,8 @@ extern crate itertools; extern crate ansi_term; extern crate handlebars; +extern crate serde; +#[macro_use] extern crate serde_derive; #[macro_use] extern crate failure; extern crate clap; diff --git a/lib/core/libimagrt/src/logger.rs b/lib/core/libimagrt/src/logger.rs index ef586bbb..8aabcb5e 100644 --- a/lib/core/libimagrt/src/logger.rs +++ b/lib/core/libimagrt/src/logger.rs @@ -349,79 +349,84 @@ mod log_lvl_aggregate { fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>) -> Result> { - // Helper macro to return the error from Some(Err(_)) and map everything else to an - // Option<_> - macro_rules! inner_try { - ($v:expr) => { - match $v { - Some(Ok(v)) => Some(v), - Some(Err(e)) => return Err(e), - None => None, + use toml_query::read::Partial; + use std::convert::TryInto; + + #[derive(Serialize, Deserialize, Debug)] + struct LoggingModuleConfig { + pub destinations: Option>, + pub level: Option, + pub enabled: bool, + } + + #[derive(Serialize, Deserialize, Debug)] + enum LogLevel { + #[serde(rename = "trace")] + Trace, + + #[serde(rename = "debug")] + Debug, + + #[serde(rename = "info")] + Info, + + #[serde(rename = "warn")] + Warn, + + #[serde(rename = "error")] + Error, + } + + impl Into for LogLevel { + fn into(self) -> Level { + match self { + LogLevel::Trace => Level::Trace, + LogLevel::Debug => Level::Debug, + LogLevel::Info => Level::Info, + LogLevel::Warn => Level::Warn, + LogLevel::Error => Level::Error, } } - }; + } + + #[derive(Serialize, Deserialize, Debug)] + struct LoggingModuleConfigMap(BTreeMap); + + impl<'a> Partial<'a> for LoggingModuleConfigMap { + const LOCATION: &'static str = "imag.logging.modules"; + type Output = Self; + } + + impl TryInto> for LoggingModuleConfigMap { + type Error = Error; + + fn try_into(self) -> Result> { + let mut map = BTreeMap::new(); + + for (key, value) in self.0.into_iter() { + map.insert(key, ModuleSettings { + enabled: value.enabled, + level: value.level.map(Into::into), + destinations: match value.destinations { + None => None, + Some(ds) => Some(ds + .iter() + .map(Deref::deref) + .map(translate_destination) + .collect::>>()?) + }, + }); + } + + Ok(map) + } + } match config { - Some(cfg) => match cfg.read("imag.logging.modules").map_err(Error::from) { - Ok(Some(&Value::Table(ref t))) => { - // translate the module settings from the table `t` - let mut settings = BTreeMap::new(); - - for (module_name, v) in t { - let destinations = inner_try! { - v.read("destinations") - .context("Failed reading header 'destinations'") - .map_err(Error::from) - .context(EM::TomlQueryError)? - .map(|val| { - val.as_array() - .ok_or_else(|| { - let msg = "Type error at 'imag.logging.modules..destinations', expected 'Array'"; - Error::from(err_msg(msg)) - }) - .and_then(translate_destinations) - }) - }; - - let level = inner_try! { - v.read_string("level") - .context("Failed reading header 'level'") - .map_err(Error::from) - .context(EM::TomlQueryError)? - .map(|s| match_log_level_str(&s)) - }; - - let enabled = v.read("enabled") - .map_err(Error::from) - .context(EM::TomlQueryError)? - .map(|v| v.as_bool().unwrap_or(false)) - .ok_or_else(|| { - let msg = "Type error at 'imag.logging.modules..enabled', expected 'Boolean'"; - Error::from(err_msg(msg)) - })?; - - let module_settings = ModuleSettings { - enabled: enabled, - level: level, - destinations: destinations, - }; - - // We don't care whether there was a value, we override it. - let _ = settings.insert(module_name.to_owned(), module_settings); - } - - Ok(settings) - }, - Ok(Some(_)) => { - let msg = "Type error at 'imag.logging.modules', expected 'Table'"; - Err(Error::from(err_msg(msg))) - }, - Ok(None) => { - // No modules configured. This is okay! - Ok(BTreeMap::new()) - }, - Err(e) => Err(e).context(EM::TomlQueryError).map_err(Error::from), - }, + Some(cfg) => cfg.read_partial::()? + .ok_or_else(|| err_msg("Logging configuration missing"))? + .try_into() + .map_err(Error::from), None => { write!(stderr(), "No Configuration.").ok(); write!(stderr(), "cannot find module-settings for logging.").ok();