This commit is contained in:
nora 2021-12-19 15:37:15 +01:00
parent f1e1cbd0a1
commit 267a67e441
6 changed files with 189 additions and 10 deletions

104
Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@ -79,6 +88,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.112"
@ -140,6 +155,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
[[package]]
name = "once_cell"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -165,6 +186,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "pin-project-lite"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
[[package]]
name = "proc-macro2"
version = "1.0.34"
@ -234,9 +261,20 @@ dependencies = [
"crossterm 0.22.1",
"serde",
"toml",
"tracing",
"tracing-subscriber",
"tui",
]
[[package]]
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
dependencies = [
"lazy_static",
]
[[package]]
name = "signal-hook"
version = "0.3.12"
@ -296,6 +334,15 @@ dependencies = [
"redox_termios",
]
[[package]]
name = "thread_local"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
dependencies = [
"once_cell",
]
[[package]]
name = "toml"
version = "0.5.8"
@ -305,6 +352,63 @@ dependencies = [
"serde",
]
[[package]]
name = "tracing"
version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4"
dependencies = [
"lazy_static",
]
[[package]]
name = "tracing-log"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3"
dependencies = [
"lazy_static",
"log",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245da694cc7fc4729f3f418b304cb57789f1bed2a78c575407ab8a23f53cb4d3"
dependencies = [
"ansi_term",
"sharded-slab",
"smallvec",
"thread_local",
"tracing-core",
"tracing-log",
]
[[package]]
name = "tui"
version = "0.16.0"

View file

@ -9,4 +9,6 @@ edition = "2021"
crossterm = "0.22.1"
serde = { version = "1.0.132", features = ["derive"] }
toml = "0.5.8"
tracing = "0.1.29"
tracing-subscriber = "0.3.3"
tui = { version = "0.16.0", features = ["crossterm"] }

6
service-manager.log Normal file
View file

@ -0,0 +1,6 @@
0.000298909s INFO service_manager: Starting service-manager...
at src/main.rs:94
0.002233976s INFO service_manager::controller: Entering main loop
at src/controller.rs:23

View file

@ -10,6 +10,7 @@ use std::process::{Child, Command, Stdio};
use std::sync::mpsc::TryRecvError;
use std::sync::{mpsc, Arc, Mutex};
use std::time::Duration;
use tracing::{error, info, trace_span};
use tui::backend::Backend;
use tui::widgets::TableState;
use tui::Terminal;
@ -19,6 +20,8 @@ const STDIO_SEND_BUF_SIZE: usize = 512;
pub type StdioSendBuf = ([u8; STDIO_SEND_BUF_SIZE], usize);
pub fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> SmResult {
info!("Entering main loop");
loop {
terminal.draw(|f| view::render_ui(f, &mut app))?;
@ -183,6 +186,8 @@ impl App {
fn start_service(&mut self, index: usize) -> SmResult {
let service = &mut self.table.services[index];
trace_span!("Starting service", name = %service.name);
*service.status.lock()? = ServiceStatus::Running;
let mut cmd = Command::new("sh");
@ -219,14 +224,20 @@ impl App {
let service_status = service.status.clone();
std::thread::spawn(move || {
match child_process_thread(child, stdout_send, service_status, terminate_recv) {
Ok(_) => {}
Err(e) => {
let _ = std::fs::write("error.txt", e.to_string());
let spawn_result = std::thread::Builder::new()
.name(format!("worker-{}", service.name))
.spawn(move || {
match child_process_thread(child, stdout_send, service_status, terminate_recv) {
Ok(_) => {}
Err(err) => {
error!(error = %err, "Error processing service");
}
}
}
});
});
if let Err(err) = spawn_result {
error!(error = %err, "Error spawning thread");
}
Ok(())
}
@ -244,6 +255,30 @@ fn child_process_thread(
.take()
.ok_or(SmError::Bug("Stdout of child could not be taken"))?;
let mut stderr = child
.stderr
.take()
.ok_or(SmError::Bug("Stderr of child could not be taken"))?;
let stdout_send_2 = stdout_send.clone();
std::thread::spawn(move || {
let mut stderr_buf = [0; STDIO_SEND_BUF_SIZE];
match stderr.read(&mut stderr_buf) {
Ok(0) => {}
Ok(n) => {
let result = stdout_send_2
.send((stderr_buf, n))
.map_err(|_| SmError::Bug("Failed to send stderr to main thread"));
if let Err(err) = result {
error!(error = %err);
}
}
Err(err) if err.kind() == io::ErrorKind::Interrupted => {}
Err(err) => error!(error = %err, "Error reading from stderr"),
};
});
let result = loop {
match terminate_channel.try_recv() {
Ok(_) | Err(TryRecvError::Disconnected) => break Ok(()),
@ -251,9 +286,8 @@ fn child_process_thread(
}
let mut stdout_buf = [0; STDIO_SEND_BUF_SIZE];
match stdout.read(&mut stdout_buf) {
Ok(0) => continue,
Ok(0) => {}
Ok(n) => {
stdout_send
.send((stdout_buf, n))
@ -262,6 +296,22 @@ fn child_process_thread(
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => break Err(e.into()),
};
match child.try_wait() {
Ok(None) => {}
Ok(Some(status)) => {
let mut status_lock = service_status.lock().map_err(|_| SmError::MutexPoisoned)?;
*status_lock = match status.code() {
Some(0) => ServiceStatus::Exited,
Some(code) => ServiceStatus::Failed(code),
None => ServiceStatus::Killed,
};
return Ok(());
}
Err(e) => break Err(e.into()),
}
};
match child.kill() {

View file

@ -7,8 +7,10 @@ use crossterm::execute;
use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
use std::fs::File;
use std::io::StdoutLock;
use std::{env, fs, io};
use tracing::info;
use tui::backend::CrosstermBackend;
use tui::Terminal;
@ -16,6 +18,8 @@ use crate::model::config::Config;
use crate::model::App;
fn main() {
setup_logging();
let file_path = env::args()
.nth(1)
.or_else(|| env::var("SERVICE_MANAGER_CONFIG_PATH").ok())
@ -77,6 +81,19 @@ or use the environment variable SERVICE_MANAGER_CONFIG_PATH"
}
}
fn setup_logging() {
let log_file = File::create("service-manager.log").unwrap();
tracing_subscriber::fmt()
.with_timer(tracing_subscriber::fmt::time::uptime())
.with_ansi(false)
.pretty()
.with_writer(log_file)
.init();
info!("Starting service-manager...");
}
fn setup_terminal(mut stdout: StdoutLock) -> io::Result<Terminal<CrosstermBackend<StdoutLock>>> {
enable_raw_mode()?;
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;

View file

@ -41,7 +41,7 @@ pub enum ServiceStatus {
NotStarted,
Running,
Exited,
Failed(u8),
Failed(i32),
Killed,
}