diff --git a/Cargo.lock b/Cargo.lock index 2dfc683..6278ecc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "ansi_term" version = "0.11.0" @@ -352,6 +354,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e7111ab..b791192 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ futures = "0.3" tokio = { version = "1", features = ["rt-multi-thread", "macros", "time"] } clap = "2" fern = "0.6" -log = "0.4" +log = { version = "0.4", features = ["serde"] } chrono = "0.4" serde = { version = "1", features = ["derive"] } tokio-icmp-echo = "0.4" diff --git a/config.toml.sample b/config.toml.sample index 25de410..d97fe2c 100644 --- a/config.toml.sample +++ b/config.toml.sample @@ -6,6 +6,11 @@ listener = "[::]:9898" # The format here is `"host" = interval in milliseconds`, so these examples # will ping the primary and secondary IP of cloudflare's 1.1.1.1 DNS service # every 500ms, or twice per second. -[hosts] +[ping.hosts] "1.1.1.1" = 500 "1.0.0.1" = 500 + +# Configure logging is also possible here instead of using the CLI. If both are +# specified, the more verbose of the two will be used. +# [log] +# level = "ERROR" diff --git a/src/config.rs b/src/config.rs index f53b18e..ceb0612 100644 --- a/src/config.rs +++ b/src/config.rs @@ -20,15 +20,35 @@ use anyhow::{Context, Result}; use clap::{clap_app, crate_authors, crate_description, crate_name, crate_version}; use log::info; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use std::collections::HashMap; -#[derive(Serialize, Deserialize, Clone)] +#[derive(Deserialize, Clone)] pub(crate) struct Config { pub(crate) listener: std::net::SocketAddr, + pub(crate) ping: PingConfig, + #[serde(default)] + pub(crate) log: LogConfig, +} + +#[derive(Deserialize, Clone)] +pub(crate) struct PingConfig { pub(crate) hosts: HashMap, } +#[derive(Deserialize, Clone)] +pub(crate) struct LogConfig { + pub(crate) level: log::LevelFilter, +} + +impl Default for LogConfig { + fn default() -> Self { + Self { + level: log::LevelFilter::Error, + } + } +} + fn setup_clap() -> clap::ArgMatches<'static> { clap_app!(myapp => (name: crate_name!()) @@ -42,14 +62,7 @@ fn setup_clap() -> clap::ArgMatches<'static> { .get_matches() } -fn setup_fern(level: u64) { - let level = match level { - 0 => log::LevelFilter::Error, - 1 => log::LevelFilter::Warn, - 2 => log::LevelFilter::Info, - 3 => log::LevelFilter::Debug, - _ => log::LevelFilter::Trace, - }; +fn setup_fern(level: log::LevelFilter) { match fern::Dispatch::new() .format(|out, message, record| { out.finish(format_args!( @@ -77,9 +90,22 @@ fn read_config(path: &str) -> Result { pub(crate) fn setup_app() -> Result { let clap = setup_clap(); - setup_fern(clap.occurrences_of("v")); let config_path = clap .value_of("config") .context("Got no config file. clap should've catched this")?; - Ok(read_config(config_path).context("Couldn't read config file!")?) + let config = read_config(config_path).context("Couldn't read config file!")?; + setup_fern(determine_level(clap.occurrences_of("v"), config.log.level)); + Ok(config) +} + +fn determine_level(verbose_occurrences: u64, config_level: log::LevelFilter) -> log::LevelFilter { + let cli_level = match verbose_occurrences { + 0 => log::LevelFilter::Error, + 1 => log::LevelFilter::Warn, + 2 => log::LevelFilter::Info, + 3 => log::LevelFilter::Debug, + _ => log::LevelFilter::Trace, + }; + + Ord::max(cli_level, config_level) } diff --git a/src/ping.rs b/src/ping.rs index e4894d8..885e3ff 100644 --- a/src/ping.rs +++ b/src/ping.rs @@ -44,7 +44,7 @@ lazy_static! { pub(crate) async fn start_pinging_hosts(config: &Config) -> Result<()> { let pinger = Pinger::new().await.context("Couldn't create pinger")?; let mut handles = vec![]; - for (host, interval) in config.hosts.clone() { + for (host, interval) in config.ping.hosts.clone() { info!("Spawn ping task for {}", host); handles.push(tokio::spawn(ping_host(pinger.clone(), host, interval))); }