Skip to content

Commit

Permalink
Write logs to files (and also copy to stdout), keep stdout on windows…
Browse files Browse the repository at this point in the history
… in debug build
  • Loading branch information
nazar-pc committed Dec 16, 2023
1 parent c2696e3 commit b11dd08
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 27 deletions.
44 changes: 44 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ atomic = "0.5.3"
bytesize = "1.3.0"
dark-light = "1.0.0"
dirs = "5.0.1"
duct = "0.13.6"
event-listener-primitives = "2.0.1"
file-rotate = "0.7.5"
futures = "0.3.29"
gtk = { version = "0.7.3", package = "gtk4" }
hex = "0.4.3"
Expand Down
2 changes: 1 addition & 1 deletion src/backend/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl RawConfig {
return Err(RawConfigError::FailedToDetermineConfigDirectory);
};

let app_config_dir = config_local_dir.join("space-acres");
let app_config_dir = config_local_dir.join(env!("CARGO_PKG_NAME"));
let config_file_path = match fs::create_dir(&app_config_dir).await {
Ok(()) => app_config_dir.join("config.json"),
Err(error) => {
Expand Down
151 changes: 125 additions & 26 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![windows_subsystem = "windows"]
#![cfg_attr(debug_assertions, windows_subsystem = "windows")]
#![feature(const_option, trait_alias, try_blocks)]

mod backend;
Expand All @@ -10,24 +10,35 @@ use crate::frontend::configuration::{ConfigurationInput, ConfigurationOutput, Co
use crate::frontend::loading::{LoadingInput, LoadingView};
use crate::frontend::running::{RunningInput, RunningView};
use atomic::Atomic;
use duct::cmd;
use file_rotate::compression::Compression;
use file_rotate::suffix::AppendCount;
use file_rotate::{ContentLimit, FileRotate};
use futures::channel::mpsc;
use futures::{select, FutureExt, SinkExt, StreamExt};
use gtk::prelude::*;
use relm4::prelude::*;
use relm4::RELM_THREADS;
use std::future::Future;
use std::process::{Command, ExitCode, Stdio, Termination};
use std::io::{Read, Write};
use std::process::{ExitCode, Termination};
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread::available_parallelism;
use std::{env, io, process};
use std::{env, fs, io, process};
use subspace_farmer::utils::{run_future_in_dedicated_thread, AsyncJoinOnDrop};
use subspace_proof_of_space::chia::ChiaTable;
use tracing::{info, warn};
use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::prelude::*;
use tracing_subscriber::EnvFilter;

/// Number of log files to keep
const LOG_FILE_LIMIT_COUNT: usize = 5;
/// Size of one log file
const LOG_FILE_LIMIT_SIZE: usize = 1024 * 1024 * 10;
const LOG_READ_BUFFER: usize = 1024 * 1024;

#[derive(Debug, Copy, Clone)]
enum AppStatusCode {
Exit,
Expand Down Expand Up @@ -509,6 +520,12 @@ fn app() -> AppStatusCode {
)
.init();

info!(
"Starting {} {}",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION")
);

// The default in `relm4` is `1`, set this back to Tokio's default
RELM_THREADS
.set(
Expand Down Expand Up @@ -536,39 +553,121 @@ fn app() -> AppStatusCode {
exit_status_code: Arc::clone(&exit_status_code),
});

exit_status_code.load(Ordering::Acquire)
let exit_status_code = exit_status_code.load(Ordering::Acquire);
info!(
?exit_status_code,
"Exiting {} {}",
env!("CARGO_PKG_NAME"),
env!("CARGO_PKG_VERSION")
);
exit_status_code
}

fn supervisor() -> io::Result<()> {
let maybe_app_data_dir = dirs::data_local_dir()
.map(|data_local_dir| data_local_dir.join(env!("CARGO_PKG_NAME")))
.and_then(|app_data_dir| {
if !app_data_dir.exists() {
if let Err(error) = fs::create_dir_all(&app_data_dir) {
eprintln!(
"App data directory \"{}\" doesn't exist and can't be created: {}",
app_data_dir.display(),
error
);
return None;
}
}

Some(app_data_dir)
});
let mut maybe_logger = maybe_app_data_dir.as_ref().map(|app_data_dir| {
FileRotate::new(
app_data_dir.join("space-acres.log"),
AppendCount::new(LOG_FILE_LIMIT_COUNT),
ContentLimit::Bytes(LOG_FILE_LIMIT_SIZE),
Compression::OnRotate(0),
#[cfg(unix)]
None,
)
});

let mut log_read_buffer = vec![0u8; LOG_READ_BUFFER];

loop {
let mut child_process = Command::new(env::current_exe()?)
let expression = cmd!(env::current_exe()?)
.env("CHILD_PROCESS", "1")
.stdin(Stdio::null())
// TODO: Use pipes and capture stdout/stderr to write logs to files
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()?;

match child_process.wait()?.code() {
Some(status_code) => {
match AppStatusCode::from_status_code(status_code) {
AppStatusCode::Exit => {
// Exited gracefully
info!("Application exited gracefully");
break;
}
AppStatusCode::Restart => {
info!("Restarting application");
continue;
.stderr_to_stdout()
// We use non-zero status codes and they don't mean error necessarily
.unchecked();

let exit_status = if let Some(logger) = maybe_logger.as_mut() {
let mut expression = expression.reader()?;

let mut stdout = io::stdout();
loop {
match expression.read(&mut log_read_buffer) {
Ok(bytes_count) => {
if bytes_count == 0 {
break;
}

let write_result: io::Result<()> = try {
stdout.write_all(&log_read_buffer[..bytes_count])?;
logger.write_all(&log_read_buffer[..bytes_count])?;
};

if let Err(error) = write_result {
eprintln!("Error while writing output of child process: {error}");
break;
}
}
AppStatusCode::Unknown(status_code) => {
warn!(%status_code, "Application exited with unexpected status code");
process::exit(status_code);
Err(error) => {
if error.kind() == io::ErrorKind::Interrupted {
// Try again
continue;
}
eprintln!("Error while reading output of child process: {error}");
break;
}
}
}

stdout.flush()?;
if let Err(error) = logger.flush() {
eprintln!("Error while flushing logs: {error}");
}

match expression.try_wait()? {
Some(output) => output.status,
None => {
return Err(io::Error::new(
io::ErrorKind::Other,
"Logs writing ended before child process did, exiting",
));
}
}
} else {
eprintln!("App data directory doesn't exist, not creating log file");
expression.run()?.status
};

match exit_status.code() {
Some(status_code) => match AppStatusCode::from_status_code(status_code) {
AppStatusCode::Exit => {
eprintln!("Application exited gracefully");
break;
}
AppStatusCode::Restart => {
eprintln!("Restarting application");
continue;
}
AppStatusCode::Unknown(status_code) => {
eprintln!("Application exited with unexpected status code {status_code}");
process::exit(status_code);
}
},
None => {
warn!("Application terminated by signal");
eprintln!("Application terminated by signal");
break;
}
}
Expand Down

0 comments on commit b11dd08

Please sign in to comment.