diff --git a/Cargo.lock b/Cargo.lock index acb4646..6bb7b3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -523,9 +523,11 @@ dependencies = [ "chrono", "dingtalk", "lazy_static", + "log", "rust_util", "serde", "serde_json", + "simple-logging", "tokio", ] @@ -1059,6 +1061,17 @@ dependencies = [ "libc", ] +[[package]] +name = "simple-logging" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00d48e85675326bb182a2286ea7c1a0b264333ae10f27a937a72be08628b542" +dependencies = [ + "lazy_static", + "log", + "thread-id", +] + [[package]] name = "slab" version = "0.4.2" @@ -1135,6 +1148,17 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "thread-id" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" +dependencies = [ + "libc", + "redox_syscall", + "winapi 0.3.8", +] + [[package]] name = "time" version = "0.1.43" diff --git a/Cargo.toml b/Cargo.toml index 479c4b8..b54eb35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,15 +7,16 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tokio = { version = "0.2.6", features = ["full"] } +tokio = { version = "0.2", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -argparse = "0.2.2" -rust_util = "0.6.3" -dingtalk = "1.3.2" -chrono = "0.4.11" -lazy_static = "1.4.0" -# log = "0.4.8" +argparse = "0.2" +rust_util = "0.6" +dingtalk = "1.3" +chrono = "0.4" +lazy_static = "1.4" +log = "0.4" +simple-logging = "2.0" [profile.release] opt-level = 'z' diff --git a/keeprunning.service b/keeprunning.service new file mode 100644 index 0000000..90f77e1 --- /dev/null +++ b/keeprunning.service @@ -0,0 +1,11 @@ +[Unit] +Description=keeprunningd +After=network-online.target +[Service] +Type=simple +ExecStart=/usr/sbin/keeprunningd +KillMode=process +Restart=on-failure +RestartSec=1min +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 8a1c5e9..7ed4658 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ #[macro_use] extern crate lazy_static; -#[macro_use] extern crate rust_util; +#[macro_use] extern crate log; use std::{ collections::HashMap, fs, panic, thread, time::Duration, process::Command, sync::{ Arc, Mutex } }; +use log::LevelFilter; use chrono::prelude::*; use serde::{ Deserialize, Serialize }; use rust_util::{ util_str::read_str_to_lines, util_file::locate_file }; @@ -27,8 +28,14 @@ lazy_static!{ } fn main() { + if let Err(_) = simple_logging::log_to_file("/var/log/keeprunningd.log", LevelFilter::Info) { + if let Err(_) = simple_logging::log_to_file("/tmp/keeprunningd.log", LevelFilter::Info) { + simple_logging::log_to_stderr(LevelFilter::Info); + } + } + panic::set_hook(Box::new(|panic_info| { - failure!("Panic in running keeprunningd: {:?}", panic_info); + error!("Panic in running keeprunningd: {:?}", panic_info); })); let keep_running_config = match parse_keep_running_config() { Some(c) => c, None => return, @@ -36,7 +43,7 @@ fn main() { let keep_running_config = Arc::new(keep_running_config); for check_cnt in 0.. { - information!("Check index: {} @{:?}", check_cnt, Local::now()); + info!("Check index: {} @{:?}", check_cnt, Local::now()); keep_runningd(keep_running_config.clone()); thread::sleep(Duration::from_secs(keep_running_config.check_inverval_secs.unwrap_or(60 * 60))); } @@ -51,32 +58,32 @@ fn parse_keep_running_config() -> Option { let config_file = match config_file_opt { None => { - failure!("Cannot find config file!"); + error!("Cannot find config file!"); return None; }, Some(config_file) => { - information!("Find config file: {:?}", &config_file); + info!("Find config file: {:?}", &config_file); config_file }, }; let config_file_content = match fs::read_to_string(&config_file) { Ok(c) => c, Err(err) => { - failure!("Read config file {:?}, error: {}", &config_file, err); + error!("Read config file {:?}, error: {}", &config_file, err); return None; }, }; let keep_running_config: KeepRunningConfig = match serde_json::from_str(&config_file_content) { Ok(c) => c, Err(err) => { - failure!("Parse config file: {:?}, error: {}", &config_file, err); + error!("Parse config file: {:?}, error: {}", &config_file, err); return None; }, }; if keep_running_config.show_debug_output.unwrap_or(false) { if let Ok(json) = serde_json::to_string_pretty(&keep_running_config) { - debugging!("Config: {}", json); + debug!("Config: {}", json); } } Some(keep_running_config) @@ -106,10 +113,10 @@ fn keep_runningd(keep_running_config: Arc) { } if check_lines.is_empty() { // if check fail! - information!("Send DingTalk notification!"); + info!("Send DingTalk notification!"); use tokio::runtime; match runtime::Builder::new().basic_scheduler().enable_all().build() { - Err(err) => failure!("Prepare tokio runtime error: {}", err), + Err(err) => error!("Prepare tokio runtime error: {}", err), Ok(mut rt) => { let mut sb = String::with_capacity(1024); sb.push_str(&format!("Check failed: {}, fail count: {}", &keep_running_config_item.title, fail_count)); @@ -119,7 +126,7 @@ fn keep_runningd(keep_running_config: Arc) { } match &keep_running_config_item.restart_command { Some(restart_command) if fail_count > 1 => { - information!("Fail count is {} > 1, try restart command: {:?}", fail_count, restart_command); + info!("Fail count is {} > 1, try restart command: {:?}", fail_count, restart_command); let mut restart_command_iter = restart_command.iter(); if let Some(program) = restart_command_iter.next() { let mut cmd = Command::new(program); @@ -127,28 +134,28 @@ fn keep_runningd(keep_running_config: Arc) { cmd.arg(arg); } match cmd.spawn() { - Ok(child) => success!("Ran process success, process id: {}", child.id()), - Err(e) => failure!("Run restart command failed: {}", e), + Ok(child) => info!("Ran process success, process id: {}", child.id()), + Err(e) => error!("Run restart command failed: {}", e), } } }, _ => ( /* IGNORE */ ), } } else if keep_running_config.show_debug_output.unwrap_or(false) { - debugging!("Find: {:?}", &check_lines); + debug!("Find: {:?}", &check_lines); } } }); if let Err(err) = t.join() { - failure!("Join check thread error: {:?}", err); + error!("Join check thread error: {:?}", err); } } async fn send_notify(notify_token: &str, text: &str) { match DingTalk::from_token(¬ify_token) { - Err(err) => failure!("Prepare DingTalk error: {}", err), + Err(err) => error!("Prepare DingTalk error: {}", err), Ok(dt) => if let Err(err) = dt.send_text(text).await { - failure!("Send DingTalk message error: {}", err); + error!("Send DingTalk message error: {}", err); }, } } @@ -158,18 +165,18 @@ fn ps_aux() -> Option { cmd.arg("aux"); let output = match cmd.output() { Ok(output) => output, Err(err) => { - failure!("Run ps error: {}", err); + error!("Run ps error: {}", err); return None; }, }; if !output.status.success() { - failure!("Run 'ps aux' error: {:?}", output.status); + error!("Run 'ps aux' error: {:?}", output.status); return None; } match String::from_utf8(output.stdout) { Ok(output_str) => Some(output_str), Err(err) => { - failure!("Get ps output as utf8 error: {}", err); + error!("Get ps output as utf8 error: {}", err); None }, }