Rewrite logging config deserialization
This patch rewrites the logging config deserialization. It removes the manual traversing of the config toml structure and replaces it with types which implement `Deserialize`, which is way more convenient and easy to read (and extend). Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
parent
b1330c9916
commit
185ec25b9e
3 changed files with 78 additions and 69 deletions
|
@ -29,6 +29,8 @@ toml-query = "0.9"
|
||||||
atty = "0.2"
|
atty = "0.2"
|
||||||
failure = "0.1"
|
failure = "0.1"
|
||||||
failure_derive = "0.1"
|
failure_derive = "0.1"
|
||||||
|
serde_derive = "1"
|
||||||
|
serde = "1"
|
||||||
|
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" }
|
libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" }
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
extern crate ansi_term;
|
extern crate ansi_term;
|
||||||
extern crate handlebars;
|
extern crate handlebars;
|
||||||
|
extern crate serde;
|
||||||
|
#[macro_use] extern crate serde_derive;
|
||||||
#[macro_use] extern crate failure;
|
#[macro_use] extern crate failure;
|
||||||
|
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
|
|
|
@ -349,79 +349,84 @@ mod log_lvl_aggregate {
|
||||||
fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>)
|
fn aggregate_module_settings(_matches: &ArgMatches, config: Option<&Value>)
|
||||||
-> Result<BTreeMap<ModuleName, ModuleSettings>>
|
-> Result<BTreeMap<ModuleName, ModuleSettings>>
|
||||||
{
|
{
|
||||||
// Helper macro to return the error from Some(Err(_)) and map everything else to an
|
use toml_query::read::Partial;
|
||||||
// Option<_>
|
use std::convert::TryInto;
|
||||||
macro_rules! inner_try {
|
|
||||||
($v:expr) => {
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
match $v {
|
struct LoggingModuleConfig {
|
||||||
Some(Ok(v)) => Some(v),
|
pub destinations: Option<Vec<String>>,
|
||||||
Some(Err(e)) => return Err(e),
|
pub level: Option<LogLevel>,
|
||||||
|
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<Level> 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<String, LoggingModuleConfig>);
|
||||||
|
|
||||||
|
impl<'a> Partial<'a> for LoggingModuleConfigMap {
|
||||||
|
const LOCATION: &'static str = "imag.logging.modules";
|
||||||
|
type Output = Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<BTreeMap<String, ModuleSettings>> for LoggingModuleConfigMap {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<BTreeMap<String, ModuleSettings>> {
|
||||||
|
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,
|
None => None,
|
||||||
|
Some(ds) => Some(ds
|
||||||
|
.iter()
|
||||||
|
.map(Deref::deref)
|
||||||
|
.map(translate_destination)
|
||||||
|
.collect::<Result<Vec<LogDestination>>>()?)
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
match config {
|
match config {
|
||||||
Some(cfg) => match cfg.read("imag.logging.modules").map_err(Error::from) {
|
Some(cfg) => cfg.read_partial::<LoggingModuleConfigMap>()?
|
||||||
Ok(Some(&Value::Table(ref t))) => {
|
.ok_or_else(|| err_msg("Logging configuration missing"))?
|
||||||
// translate the module settings from the table `t`
|
.try_into()
|
||||||
let mut settings = BTreeMap::new();
|
.map_err(Error::from),
|
||||||
|
|
||||||
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.<mod>.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.<mod>.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),
|
|
||||||
},
|
|
||||||
None => {
|
None => {
|
||||||
write!(stderr(), "No Configuration.").ok();
|
write!(stderr(), "No Configuration.").ok();
|
||||||
write!(stderr(), "cannot find module-settings for logging.").ok();
|
write!(stderr(), "cannot find module-settings for logging.").ok();
|
||||||
|
|
Loading…
Reference in a new issue