feat: use log to file
This commit is contained in:
24
Cargo.lock
generated
24
Cargo.lock
generated
@@ -523,9 +523,11 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"dingtalk",
|
"dingtalk",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"log",
|
||||||
"rust_util",
|
"rust_util",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"simple-logging",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1059,6 +1061,17 @@ dependencies = [
|
|||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -1135,6 +1148,17 @@ dependencies = [
|
|||||||
"winapi 0.3.8",
|
"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]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.1.43"
|
version = "0.1.43"
|
||||||
|
|||||||
15
Cargo.toml
15
Cargo.toml
@@ -7,15 +7,16 @@ edition = "2018"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { version = "0.2.6", features = ["full"] }
|
tokio = { version = "0.2", features = ["full"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
argparse = "0.2.2"
|
argparse = "0.2"
|
||||||
rust_util = "0.6.3"
|
rust_util = "0.6"
|
||||||
dingtalk = "1.3.2"
|
dingtalk = "1.3"
|
||||||
chrono = "0.4.11"
|
chrono = "0.4"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4"
|
||||||
# log = "0.4.8"
|
log = "0.4"
|
||||||
|
simple-logging = "2.0"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 'z'
|
opt-level = 'z'
|
||||||
|
|||||||
11
keeprunning.service
Normal file
11
keeprunning.service
Normal file
@@ -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
|
||||||
47
src/main.rs
47
src/main.rs
@@ -1,7 +1,8 @@
|
|||||||
#[macro_use] extern crate lazy_static;
|
#[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 std::{ collections::HashMap, fs, panic, thread, time::Duration, process::Command, sync::{ Arc, Mutex } };
|
||||||
|
use log::LevelFilter;
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use serde::{ Deserialize, Serialize };
|
use serde::{ Deserialize, Serialize };
|
||||||
use rust_util::{ util_str::read_str_to_lines, util_file::locate_file };
|
use rust_util::{ util_str::read_str_to_lines, util_file::locate_file };
|
||||||
@@ -27,8 +28,14 @@ lazy_static!{
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
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| {
|
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() {
|
let keep_running_config = match parse_keep_running_config() {
|
||||||
Some(c) => c, None => return,
|
Some(c) => c, None => return,
|
||||||
@@ -36,7 +43,7 @@ fn main() {
|
|||||||
|
|
||||||
let keep_running_config = Arc::new(keep_running_config);
|
let keep_running_config = Arc::new(keep_running_config);
|
||||||
for check_cnt in 0.. {
|
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());
|
keep_runningd(keep_running_config.clone());
|
||||||
thread::sleep(Duration::from_secs(keep_running_config.check_inverval_secs.unwrap_or(60 * 60)));
|
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<KeepRunningConfig> {
|
|||||||
|
|
||||||
let config_file = match config_file_opt {
|
let config_file = match config_file_opt {
|
||||||
None => {
|
None => {
|
||||||
failure!("Cannot find config file!");
|
error!("Cannot find config file!");
|
||||||
return None;
|
return None;
|
||||||
},
|
},
|
||||||
Some(config_file) => {
|
Some(config_file) => {
|
||||||
information!("Find config file: {:?}", &config_file);
|
info!("Find config file: {:?}", &config_file);
|
||||||
config_file
|
config_file
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let config_file_content = match fs::read_to_string(&config_file) {
|
let config_file_content = match fs::read_to_string(&config_file) {
|
||||||
Ok(c) => c, Err(err) => {
|
Ok(c) => c, Err(err) => {
|
||||||
failure!("Read config file {:?}, error: {}", &config_file, err);
|
error!("Read config file {:?}, error: {}", &config_file, err);
|
||||||
return None;
|
return None;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let keep_running_config: KeepRunningConfig = match serde_json::from_str(&config_file_content) {
|
let keep_running_config: KeepRunningConfig = match serde_json::from_str(&config_file_content) {
|
||||||
Ok(c) => c, Err(err) => {
|
Ok(c) => c, Err(err) => {
|
||||||
failure!("Parse config file: {:?}, error: {}", &config_file, err);
|
error!("Parse config file: {:?}, error: {}", &config_file, err);
|
||||||
return None;
|
return None;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if keep_running_config.show_debug_output.unwrap_or(false) {
|
if keep_running_config.show_debug_output.unwrap_or(false) {
|
||||||
if let Ok(json) = serde_json::to_string_pretty(&keep_running_config) {
|
if let Ok(json) = serde_json::to_string_pretty(&keep_running_config) {
|
||||||
debugging!("Config: {}", json);
|
debug!("Config: {}", json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(keep_running_config)
|
Some(keep_running_config)
|
||||||
@@ -106,10 +113,10 @@ fn keep_runningd(keep_running_config: Arc<KeepRunningConfig>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if check_lines.is_empty() { // if check fail!
|
if check_lines.is_empty() { // if check fail!
|
||||||
information!("Send DingTalk notification!");
|
info!("Send DingTalk notification!");
|
||||||
use tokio::runtime;
|
use tokio::runtime;
|
||||||
match runtime::Builder::new().basic_scheduler().enable_all().build() {
|
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) => {
|
Ok(mut rt) => {
|
||||||
let mut sb = String::with_capacity(1024);
|
let mut sb = String::with_capacity(1024);
|
||||||
sb.push_str(&format!("Check failed: {}, fail count: {}", &keep_running_config_item.title, fail_count));
|
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<KeepRunningConfig>) {
|
|||||||
}
|
}
|
||||||
match &keep_running_config_item.restart_command {
|
match &keep_running_config_item.restart_command {
|
||||||
Some(restart_command) if fail_count > 1 => {
|
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();
|
let mut restart_command_iter = restart_command.iter();
|
||||||
if let Some(program) = restart_command_iter.next() {
|
if let Some(program) = restart_command_iter.next() {
|
||||||
let mut cmd = Command::new(program);
|
let mut cmd = Command::new(program);
|
||||||
@@ -127,28 +134,28 @@ fn keep_runningd(keep_running_config: Arc<KeepRunningConfig>) {
|
|||||||
cmd.arg(arg);
|
cmd.arg(arg);
|
||||||
}
|
}
|
||||||
match cmd.spawn() {
|
match cmd.spawn() {
|
||||||
Ok(child) => success!("Ran process success, process id: {}", child.id()),
|
Ok(child) => info!("Ran process success, process id: {}", child.id()),
|
||||||
Err(e) => failure!("Run restart command failed: {}", e),
|
Err(e) => error!("Run restart command failed: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => ( /* IGNORE */ ),
|
_ => ( /* IGNORE */ ),
|
||||||
}
|
}
|
||||||
} else if keep_running_config.show_debug_output.unwrap_or(false) {
|
} 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() {
|
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) {
|
async fn send_notify(notify_token: &str, text: &str) {
|
||||||
match DingTalk::from_token(¬ify_token) {
|
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 {
|
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<String> {
|
|||||||
cmd.arg("aux");
|
cmd.arg("aux");
|
||||||
let output = match cmd.output() {
|
let output = match cmd.output() {
|
||||||
Ok(output) => output, Err(err) => {
|
Ok(output) => output, Err(err) => {
|
||||||
failure!("Run ps error: {}", err);
|
error!("Run ps error: {}", err);
|
||||||
return None;
|
return None;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
failure!("Run 'ps aux' error: {:?}", output.status);
|
error!("Run 'ps aux' error: {:?}", output.status);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match String::from_utf8(output.stdout) {
|
match String::from_utf8(output.stdout) {
|
||||||
Ok(output_str) => Some(output_str),
|
Ok(output_str) => Some(output_str),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
failure!("Get ps output as utf8 error: {}", err);
|
error!("Get ps output as utf8 error: {}", err);
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user