From e6adb5282d4007133070cecb9b27353fce532ce1 Mon Sep 17 00:00:00 2001 From: jb-alvarado Date: Fri, 25 Feb 2022 16:22:29 +0100 Subject: [PATCH] create LogMailer for using it in CombinedLogger --- examples/logging.rs | 68 ++++++++++++++++++++- src/main.rs | 20 +++--- src/output/desktop.rs | 22 ++++--- src/utils/json_reader.rs | 8 ++- src/utils/logging.rs | 129 +++++++++++++++++++++++++++++++++++++++ src/utils/messenger.rs | 112 --------------------------------- src/utils/mod.rs | 4 +- src/utils/playlist.rs | 26 ++++---- 8 files changed, 238 insertions(+), 151 deletions(-) create mode 100644 src/utils/logging.rs delete mode 100644 src/utils/messenger.rs diff --git a/examples/logging.rs b/examples/logging.rs index 68d3f213..a03d43d3 100644 --- a/examples/logging.rs +++ b/examples/logging.rs @@ -5,6 +5,59 @@ use simplelog::*; use file_rotate::{compression::Compression, suffix::AppendCount, ContentLimit, FileRotate}; +// use crate::{Config, SharedLogger}; +use log::{Level, LevelFilter, Log, Metadata, Record}; + +pub struct LogMailer { + level: LevelFilter, + config: Config, +} + +impl LogMailer { + pub fn new(log_level: LevelFilter, config: Config) -> Box { + Box::new(LogMailer { + level: log_level, + config, + }) + } +} + +impl Log for LogMailer { + fn enabled(&self, metadata: &Metadata<'_>) -> bool { + metadata.level() <= self.level + } + + fn log(&self, record: &Record<'_>) { + if self.enabled(record.metadata()) { + match record.level() { + Level::Error => { + println!("Send Error Mail: {:?}\n{:?}", record, self.config) + }, + Level::Warn => { + println!("Send Warn Mail: {:?}", record.args()) + } + _ => () + } + } + } + + fn flush(&self) {} +} + +impl SharedLogger for LogMailer { + fn level(&self) -> LevelFilter { + self.level + } + + fn config(&self) -> Option<&Config> { + Some(&self.config) + } + + fn as_log(self: Box) -> Box { + Box::new(*self) + } +} + fn main() { let log = || { FileRotate::new( @@ -19,9 +72,11 @@ fn main() { .set_target_level(LevelFilter::Off) .set_thread_level(LevelFilter::Off) .set_level_padding(LevelPadding::Left) - .set_time_to_local(true).clone(); + .set_time_to_local(true) + .clone(); - let term_config = def_config.clone() + let term_config = def_config + .clone() .set_level_color(Level::Debug, Some(Color::Ansi256(12))) .set_level_color(Level::Info, Some(Color::Ansi256(10))) .set_level_color(Level::Warn, Some(Color::Ansi256(208))) @@ -29,7 +84,13 @@ fn main() { .set_time_format_str("\x1b[30;1m[%Y-%m-%d %H:%M:%S%.3f]\x1b[0m") .build(); - let file_config = def_config.clone() + let file_config = def_config + .clone() + .set_time_format_str("[%Y-%m-%d %H:%M:%S%.3f]") + .build(); + + let mail_config = def_config + .clone() .set_time_format_str("[%Y-%m-%d %H:%M:%S%.3f]") .build(); @@ -41,6 +102,7 @@ fn main() { ColorChoice::Auto, ), WriteLogger::new(LevelFilter::Debug, file_config, log()), + LogMailer::new(LevelFilter::Warn, mail_config), ]) .unwrap(); diff --git a/src/main.rs b/src/main.rs index fd30a6dc..f8f56954 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,23 @@ +extern crate log; +extern crate simplelog; + mod filter; mod output; mod utils; +use simplelog::*; + use crate::output::desktop; -use crate::utils::{get_config, Messenger}; +use crate::utils::{get_config, init_logging}; fn main() { let config = get_config(); - let msg = Messenger::new(&config); + let logging = init_logging(&config); - // msg.debug("this is a debug"); - // msg.info("this is a info"); - // msg.warning("this is a warning"); - // msg.error("this is a error"); - // println!("{:#?}", config); + CombinedLogger::init(logging).unwrap(); + + warn!("this is a warning"); + error!("this is a error"); // folder::walk(&config.storage.path, config.storage.shuffle, &config.storage.extensions); @@ -29,5 +33,5 @@ fn main() { // println!("{:#?}", utils::get_sec()); // println!("{:#?}", utils::get_timestamp()); - desktop::play(msg, config); + desktop::play(config); } diff --git a/src/output/desktop.rs b/src/output/desktop.rs index 0ccbad49..eda3dbda 100644 --- a/src/output/desktop.rs +++ b/src/output/desktop.rs @@ -5,10 +5,12 @@ use std::{ time::Duration, }; -use crate::utils::{sec_to_time, Config, CurrentProgram, Messenger}; +use simplelog::*; -pub fn play(msg: Messenger, config: Config) { - let get_source = CurrentProgram::new(&msg, config.clone()); +use crate::utils::{sec_to_time, Config, CurrentProgram}; + +pub fn play(config: Config) { + let get_source = CurrentProgram::new(config.clone()); let dec_settings = config.processing.settings.unwrap(); let ff_log_format = format!("level+{}", config.logging.ffmpeg_level); let mut enc_cmd = vec![ @@ -35,7 +37,7 @@ pub fn play(msg: Messenger, config: Config) { enc_cmd.append(&mut enc_filter.iter().map(String::as_str).collect()); - msg.debug(format!("Encoder CMD: {:?}", enc_cmd)); + debug!("Encoder CMD: {:?}", enc_cmd); let mut enc_proc = match Command::new("ffplay") .args(enc_cmd) @@ -44,7 +46,7 @@ pub fn play(msg: Messenger, config: Config) { .spawn() { Err(e) => { - msg.error(format!("couldn't spawn encoder process: {}", e)); + error!("couldn't spawn encoder process: {}", e); panic!("couldn't spawn encoder process: {}", e) } Ok(proc) => proc, @@ -52,11 +54,11 @@ pub fn play(msg: Messenger, config: Config) { for node in get_source { // println!("Node begin: {:?}", sec_to_time(node.begin.unwrap())); - msg.info(format!( + info!( "Play for {}: {}", sec_to_time(node.out - node.seek), node.source - )); + ); let cmd = node.cmd.unwrap(); let filter = node.filter.unwrap(); @@ -70,7 +72,7 @@ pub fn play(msg: Messenger, config: Config) { } dec_cmd.append(&mut dec_settings.iter().map(String::as_str).collect()); - msg.debug(format!("Decoder CMD: {:?}", dec_cmd)); + debug!("Decoder CMD: {:?}", dec_cmd); let mut dec_proc = match Command::new("ffmpeg") .args(dec_cmd) @@ -79,7 +81,7 @@ pub fn play(msg: Messenger, config: Config) { .spawn() { Err(e) => { - msg.error(format!("couldn't spawn decoder process: {}", e)); + error!("couldn't spawn decoder process: {}", e); panic!("couldn't spawn decoder process: {}", e) } Ok(proc) => proc, @@ -111,7 +113,7 @@ pub fn play(msg: Messenger, config: Config) { sleep(Duration::from_secs(1)); match enc_proc.kill() { - Ok(_) => msg.info("Playout done...".into()), + Ok(_) => info!("Playout done..."), Err(e) => panic!("Enc error: {:?}", e), } } diff --git a/src/utils/json_reader.rs b/src/utils/json_reader.rs index c8f8f674..0d20d001 100644 --- a/src/utils/json_reader.rs +++ b/src/utils/json_reader.rs @@ -1,7 +1,9 @@ use serde::{Deserialize, Serialize}; use std::{fs::File, path::Path}; -use crate::utils::{get_date, get_sec, modified_time, time_to_sec, Config, MediaProbe, Messenger}; +use simplelog::*; + +use crate::utils::{get_date, get_sec, modified_time, time_to_sec, Config, MediaProbe}; #[derive(Debug, Serialize, Deserialize)] pub struct Playlist { @@ -29,7 +31,7 @@ pub struct Program { pub next_ad: Option, } -pub fn read_json(msg: &Messenger, config: &Config, seek: bool) -> Playlist { +pub fn read_json(config: &Config, seek: bool) -> Playlist { let mut playlist_path = Path::new(&config.playlist.path).to_owned(); let start = &config.playlist.day_start; let length = &config.playlist.length; @@ -53,7 +55,7 @@ pub fn read_json(msg: &Messenger, config: &Config, seek: bool) -> Playlist { length_sec = time_to_sec(length); } - msg.info(format!("Read Playlist: {}", ¤t_file)); + info!("Read Playlist: {}", ¤t_file); let modify = modified_time(current_file.clone()); let f = File::open(¤t_file).expect("Could not open json playlist file."); diff --git a/src/utils/logging.rs b/src/utils/logging.rs new file mode 100644 index 00000000..bef3b16f --- /dev/null +++ b/src/utils/logging.rs @@ -0,0 +1,129 @@ +extern crate log; +extern crate simplelog; + +use std::path::Path; + +use file_rotate::{compression::Compression, suffix::AppendCount, ContentLimit, FileRotate}; +use log::{Level, LevelFilter, Log, Metadata, Record}; +use simplelog::*; + +use crate::utils; + +pub struct LogMailer { + level: LevelFilter, + config: Config, +} + +impl LogMailer { + pub fn new(log_level: LevelFilter, config: Config) -> Box { + Box::new(LogMailer { + level: log_level, + config, + }) + } +} + +impl Log for LogMailer { + fn enabled(&self, metadata: &Metadata<'_>) -> bool { + metadata.level() <= self.level + } + + fn log(&self, record: &Record<'_>) { + if self.enabled(record.metadata()) { + match record.level() { + Level::Error => { + println!("Send Error Mail: {:?}\n{:?}", record, self.config) + } + Level::Warn => { + println!("Send Warn Mail: {:?}", record.args()) + } + _ => (), + } + } + } + + fn flush(&self) {} +} + +impl SharedLogger for LogMailer { + fn level(&self) -> LevelFilter { + self.level + } + + fn config(&self) -> Option<&Config> { + Some(&self.config) + } + + fn as_log(self: Box) -> Box { + Box::new(*self) + } +} + +pub fn init_logging(config: &utils::Config) -> Vec> { + let app_config = config.logging.clone(); + let mut app_logger: Vec> = vec![]; + + let log_config = simplelog::ConfigBuilder::new() + .set_thread_level(LevelFilter::Off) + .set_target_level(LevelFilter::Off) + .set_level_padding(LevelPadding::Left) + .set_time_to_local(app_config.local_time) + .clone(); + + if app_config.log_to_file { + let file_config = log_config + .clone() + .set_time_format("[%Y-%m-%d %H:%M:%S%.3f]".into()) + .build(); + let mut log_path = "logs/ffplayout.log".to_string(); + + if Path::new(&app_config.log_path).is_dir() { + log_path = Path::new(&app_config.log_path) + .join("ffplayout.log") + .display() + .to_string(); + } else if Path::new(&app_config.log_path).is_file() { + log_path = app_config.log_path + } else { + println!("Logging path not exists!") + } + + let log = || { + FileRotate::new( + log_path, + AppendCount::new(app_config.backup_count), + ContentLimit::Lines(1000), + Compression::None, + ) + }; + + app_logger.push(WriteLogger::new(LevelFilter::Debug, file_config, log())); + } else { + let term_config = log_config + .clone() + .set_level_color(Level::Debug, Some(Color::Ansi256(12))) + .set_level_color(Level::Info, Some(Color::Ansi256(10))) + .set_level_color(Level::Warn, Some(Color::Ansi256(208))) + .set_level_color(Level::Error, Some(Color::Ansi256(9))) + .set_time_format_str("\x1b[30;1m[%Y-%m-%d %H:%M:%S%.3f]\x1b[0m") + .build(); + + app_logger.push(TermLogger::new( + LevelFilter::Debug, + term_config, + TerminalMode::Mixed, + ColorChoice::Auto, + )); + } + + if config.mail.recipient.len() > 3 { + let mail_config = log_config + .clone() + .set_time_format_str("[%Y-%m-%d %H:%M:%S%.3f]") + .build(); + + app_logger.push(LogMailer::new(LevelFilter::Warn, mail_config)); + } + + app_logger +} diff --git a/src/utils/messenger.rs b/src/utils/messenger.rs deleted file mode 100644 index 6fd0adf7..00000000 --- a/src/utils/messenger.rs +++ /dev/null @@ -1,112 +0,0 @@ -extern crate log; -extern crate simplelog; - -use std::path::Path; - -use file_rotate::{compression::Compression, suffix::AppendCount, ContentLimit, FileRotate}; -use simplelog::*; - -use crate::utils::Config; - -#[derive(Debug, Clone)] -pub struct Messenger { - level: String, - // ffmpeg_level: String, -} - -impl Messenger { - pub fn new(config: &Config) -> Self { - let conf = config.logging.clone(); - let log_config = simplelog::ConfigBuilder::new() - .set_thread_level(LevelFilter::Off) - .set_target_level(LevelFilter::Off) - .set_level_padding(LevelPadding::Left) - .set_time_to_local(conf.local_time) - .clone(); - - if conf.log_to_file { - let file_config = log_config - .clone() - .set_time_format("[%Y-%m-%d %H:%M:%S%.3f]".into()) - .build(); - let mut log_path = "logs/ffplayout.log".to_string(); - - if Path::new(&conf.log_path).is_dir() { - log_path = Path::new(&conf.log_path) - .join("ffplayout.log") - .display() - .to_string(); - } else if Path::new(&conf.log_path).is_file() { - log_path = conf.log_path - } else { - println!("Logging path not exists!") - } - - let log = || { - FileRotate::new( - log_path, - AppendCount::new(conf.backup_count), - ContentLimit::Lines(1000), - Compression::None, - ) - }; - - WriteLogger::init(LevelFilter::Debug, file_config, log()).unwrap(); - } else { - let term_config = log_config - .clone() - .set_level_color(Level::Debug, Some(Color::Ansi256(12))) - .set_level_color(Level::Info, Some(Color::Ansi256(10))) - .set_level_color(Level::Warn, Some(Color::Ansi256(208))) - .set_level_color(Level::Error, Some(Color::Ansi256(9))) - .set_time_format_str("\x1b[30;1m[%Y-%m-%d %H:%M:%S%.3f]\x1b[0m") - .build(); - - TermLogger::init( - LevelFilter::Debug, - term_config, - TerminalMode::Mixed, - ColorChoice::Auto, - ) - .unwrap(); - } - - Messenger { - level: conf.log_level, - // ffmpeg_level: conf.ffmpeg_level, - } - } - - pub fn debug(&self, msg: String) { - if self.level.to_lowercase() == "debug".to_string() { - debug!("{}", msg) - } - } - - pub fn info(&self, msg: String) { - if self.level.to_lowercase() == "debug".to_string() - || self.level.to_lowercase() == "info".to_string() - { - info!("{}", msg) - } - } - - pub fn warning(&self, msg: String) { - if self.level.to_lowercase() == "debug".to_string() - || self.level.to_lowercase() == "info".to_string() - || self.level.to_lowercase() == "warning".to_string() - { - warn!("{}", msg) - } - } - - pub fn error(&self, msg: String) { - if self.level.to_lowercase() == "debug".to_string() - || self.level.to_lowercase() == "info".to_string() - || self.level.to_lowercase() == "warning".to_string() - || self.level.to_lowercase() == "error".to_string() - { - error!("{}", msg) - } - } -} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 8ea0cf6e..aaa65565 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -7,14 +7,14 @@ use std::{fs::metadata, process, time, time::UNIX_EPOCH}; mod arg_parse; mod config; mod json_reader; -mod messenger; +mod logging; mod playlist; pub use arg_parse::get_args; pub use config::{get_config, Config}; // pub use folder::walk; pub use json_reader::{read_json, Program}; -pub use messenger::Messenger; +pub use logging::init_logging; pub use playlist::CurrentProgram; #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/src/utils/playlist.rs b/src/utils/playlist.rs index bfa27121..3af4dd63 100644 --- a/src/utils/playlist.rs +++ b/src/utils/playlist.rs @@ -1,15 +1,16 @@ use std::path::Path; +use simplelog::*; + use crate::utils::{ check_sync, gen_dummy, get_delta, json_reader::{read_json, Program}, - modified_time, Config, MediaProbe, Messenger, + modified_time, Config, MediaProbe, }; use crate::filter::filter_chains; pub struct CurrentProgram { - msg: Messenger, config: Config, json_mod: String, json_path: String, @@ -19,11 +20,10 @@ pub struct CurrentProgram { } impl CurrentProgram { - pub fn new(msg: &Messenger, config: Config) -> Self { - let json = read_json(&msg, &config, true); + pub fn new(config: Config) -> Self { + let json = read_json(&config, true); Self { - msg: msg.clone(), config: config, json_mod: json.modified.unwrap(), json_path: json.current_file.unwrap(), @@ -38,7 +38,7 @@ impl CurrentProgram { if !mod_time.unwrap().to_string().eq(&self.json_mod) { // when playlist has changed, reload it - let json = read_json(&self.msg, &self.config, false); + let json = read_json(&self.config, false); self.json_mod = json.modified.unwrap(); self.nodes = json.program.into(); @@ -68,8 +68,8 @@ impl Iterator for CurrentProgram { last = true } - self.msg.debug(format!("Last: {}", self.nodes[self.idx - 1].source)); - self.msg.debug(format!("Next: {}", self.nodes[self.idx + 1].source)); + debug!("Last: {}", self.nodes[self.idx - 1].source); + debug!("Next: {}", self.nodes[self.idx + 1].source); self.idx += 1; @@ -80,7 +80,7 @@ impl Iterator for CurrentProgram { if !self.init { let delta = get_delta(¤t.begin.unwrap(), &self.config); - self.msg.debug(format!("Delta: {delta}")); + debug!("Delta: {delta}"); check_sync(delta, &self.config); } @@ -88,7 +88,7 @@ impl Iterator for CurrentProgram { self.append_probe(&mut current); self.add_filter(&mut current, last, next); } else { - self.msg.error(format!("File not found: {}", current.source)); + error!("File not found: {}", current.source); let dummy = gen_dummy(current.out - current.seek, &self.config); current.source = dummy.0; current.cmd = Some(dummy.1); @@ -105,7 +105,7 @@ impl Iterator for CurrentProgram { last = true } - let json = read_json(&self.msg, &self.config, false); + let json = read_json(&self.config, false); self.json_mod = json.modified.unwrap(); self.json_path = json.current_file.unwrap(); self.nodes = json.program.into(); @@ -119,7 +119,7 @@ impl Iterator for CurrentProgram { if !self.init { let delta = get_delta(¤t.begin.unwrap(), &self.config); - self.msg.debug(format!("Delta: {delta}")); + debug!("Delta: {delta}"); check_sync(delta, &self.config); } @@ -127,7 +127,7 @@ impl Iterator for CurrentProgram { self.append_probe(&mut current); self.add_filter(&mut current, last, next); } else { - self.msg.error(format!("File not found: {}", current.source)); + error!("File not found: {}", current.source); let dummy = gen_dummy(current.out - current.seek, &self.config); current.source = dummy.0; current.cmd = Some(dummy.1);