prevent silent errors in daemon mode (#10007)
* prevent silent errors in daemon mode * change author in Cargo.toml, add preamble to pipe.rs * set the uid and gid on daemon process, fix permission errors when writing to pid file * call setup_logger before daemonize to prevent crashing when attempting to create logfile * map_err for calls to splice and ioctl, fix spaces in Cargo.toml * split out daemonize to own repo * removed util/daemonize * renamed dep to parity-daemonize * fix(parity-clib): enable `logger` * bump parity-daemonize * remove obsolete comment Co-Authored-By: seunlanlege <seunlanlege@gmail.com> * fix(grumbles): docs and log in ParityParams * Add FIXME comment regarding @tomaka grumbles * Unify logger with the C-API in ParityParams (less type-safety with more from_raw() conversions) * Add better documentation in the `parity.h` * Apply suggestions from code review Co-Authored-By: seunlanlege <seunlanlege@gmail.com> * docs(parity lib): add link to logging issue * fix(parity-clib): JNI enable `logger` * fix(parity-clib): update `Java example` * Update example to the API changes * Remove needless printouts which can be controlled via logger instead
This commit is contained in:
committed by
Afri Schoedon
parent
12c42bce9b
commit
0f9b2218da
@@ -473,7 +473,8 @@ impl Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
fn logger_config(&self) -> LogConfig {
|
||||
/// returns logger config
|
||||
pub fn logger_config(&self) -> LogConfig {
|
||||
LogConfig {
|
||||
mode: self.args.arg_logging.clone(),
|
||||
color: !self.args.flag_no_color && !cfg!(windows),
|
||||
|
||||
@@ -111,19 +111,22 @@ mod user_defaults;
|
||||
mod whisper;
|
||||
mod db;
|
||||
|
||||
use std::io::BufReader;
|
||||
use std::fs::File;
|
||||
use hash::keccak_buffer;
|
||||
use std::io::BufReader;
|
||||
use std::sync::Arc;
|
||||
|
||||
use cli::Args;
|
||||
use configuration::{Cmd, Execute};
|
||||
use deprecated::find_deprecated;
|
||||
use ethcore_logger::setup_log;
|
||||
use hash::keccak_buffer;
|
||||
|
||||
#[cfg(feature = "memory_profiling")]
|
||||
use std::alloc::System;
|
||||
|
||||
pub use self::configuration::Configuration;
|
||||
pub use self::run::RunningClient;
|
||||
pub use parity_rpc::PubSubSession;
|
||||
pub use ethcore_logger::{Config as LoggerConfig, setup_log, RotatingLogger};
|
||||
|
||||
#[cfg(feature = "memory_profiling")]
|
||||
#[global_allocator]
|
||||
@@ -180,14 +183,13 @@ pub enum ExecutionAction {
|
||||
Running(RunningClient),
|
||||
}
|
||||
|
||||
fn execute<Cr, Rr>(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Result<ExecutionAction, String>
|
||||
fn execute<Cr, Rr>(
|
||||
command: Execute,
|
||||
logger: Arc<RotatingLogger>,
|
||||
on_client_rq: Cr, on_updater_rq: Rr) -> Result<ExecutionAction, String>
|
||||
where Cr: Fn(String) + 'static + Send,
|
||||
Rr: Fn() + 'static + Send
|
||||
{
|
||||
// TODO: move this to `main()` and expose in the C API so that users can setup logging the way
|
||||
// they want
|
||||
let logger = setup_log(&command.logger).expect("Logger is initialized only once; qed");
|
||||
|
||||
#[cfg(feature = "deadlock_detection")]
|
||||
run_deadlock_detection_thread();
|
||||
|
||||
@@ -221,14 +223,21 @@ fn execute<Cr, Rr>(command: Execute, on_client_rq: Cr, on_updater_rq: Rr) -> Res
|
||||
/// binary.
|
||||
///
|
||||
/// On error, returns what to print on stderr.
|
||||
pub fn start<Cr, Rr>(conf: Configuration, on_client_rq: Cr, on_updater_rq: Rr) -> Result<ExecutionAction, String>
|
||||
where Cr: Fn(String) + 'static + Send,
|
||||
Rr: Fn() + 'static + Send
|
||||
// FIXME: totally independent logging capability, see https://github.com/paritytech/parity-ethereum/issues/10252
|
||||
pub fn start<Cr, Rr>(
|
||||
conf: Configuration,
|
||||
logger: Arc<RotatingLogger>,
|
||||
on_client_rq: Cr,
|
||||
on_updater_rq: Rr
|
||||
) -> Result<ExecutionAction, String>
|
||||
where
|
||||
Cr: Fn(String) + 'static + Send,
|
||||
Rr: Fn() + 'static + Send
|
||||
{
|
||||
let deprecated = find_deprecated(&conf.args);
|
||||
for d in deprecated {
|
||||
println!("{}", d);
|
||||
}
|
||||
|
||||
execute(conf.into_command()?, on_client_rq, on_updater_rq)
|
||||
execute(conf.into_command()?, logger, on_client_rq, on_updater_rq)
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ pub fn setup_log(config: &Config) -> Result<Arc<RotatingLogger>, String> {
|
||||
let maybe_file = match config.file.as_ref() {
|
||||
Some(f) => Some(open_options
|
||||
.append(true).create(true).open(f)
|
||||
.map_err(|_| format!("Cannot write to log file given: {}", f))?),
|
||||
.map_err(|e| format!("Cannot write to log file given: {}, {}", f, e))?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
|
||||
@@ -26,8 +26,11 @@ extern crate log;
|
||||
extern crate panic_hook;
|
||||
extern crate parity_ethereum;
|
||||
extern crate parking_lot;
|
||||
extern crate parity_daemonize;
|
||||
extern crate ansi_term;
|
||||
|
||||
#[cfg(windows)] extern crate winapi;
|
||||
extern crate ethcore_logger;
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{remove_file, metadata, File, create_dir_all};
|
||||
@@ -36,12 +39,13 @@ use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::{process, env};
|
||||
|
||||
use ansi_term::Colour;
|
||||
use ctrlc::CtrlC;
|
||||
use dir::default_hypervisor_path;
|
||||
use fdlimit::raise_fd_limit;
|
||||
use parity_ethereum::{start, ExecutionAction};
|
||||
use parking_lot::{Condvar, Mutex};
|
||||
use ethcore_logger::setup_log;
|
||||
|
||||
const PLEASE_RESTART_EXIT_CODE: i32 = 69;
|
||||
const PARITY_EXECUTABLE_NAME: &str = "parity";
|
||||
@@ -184,11 +188,33 @@ fn main_direct(force_can_restart: bool) -> i32 {
|
||||
parity_ethereum::Configuration::parse_cli(&args).unwrap_or_else(|e| e.exit())
|
||||
};
|
||||
|
||||
let logger = setup_log(&conf.logger_config()).expect("Logger is initialized only once; qed");
|
||||
|
||||
if let Some(spec_override) = take_spec_name_override() {
|
||||
conf.args.flag_testnet = false;
|
||||
conf.args.arg_chain = spec_override;
|
||||
}
|
||||
|
||||
let handle = if let Some(ref pid) = conf.args.arg_daemon_pid_file {
|
||||
info!("{}", Colour::Blue.paint("starting in daemon mode").to_string());
|
||||
let _ = std::io::stdout().flush();
|
||||
|
||||
match parity_daemonize::daemonize(pid) {
|
||||
Ok(h) => Some(h),
|
||||
Err(e) => {
|
||||
error!(
|
||||
"{}",
|
||||
Colour::Red.paint(format!("{}", e))
|
||||
);
|
||||
// flush before returning
|
||||
let _ = std::io::stderr().flush();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let can_restart = force_can_restart || conf.args.flag_can_restart;
|
||||
|
||||
// increase max number of open files
|
||||
@@ -208,6 +234,7 @@ fn main_direct(force_can_restart: bool) -> i32 {
|
||||
let exec = if can_restart {
|
||||
start(
|
||||
conf,
|
||||
logger,
|
||||
{
|
||||
let e = exit.clone();
|
||||
let exiting = exiting.clone();
|
||||
@@ -239,10 +266,9 @@ fn main_direct(force_can_restart: bool) -> i32 {
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
} else {
|
||||
trace!(target: "mode", "Not hypervised: not setting exit handlers.");
|
||||
start(conf, move |_| {}, move || {})
|
||||
start(conf, logger, move |_| {}, move || {})
|
||||
};
|
||||
|
||||
let res = match exec {
|
||||
@@ -283,6 +309,12 @@ fn main_direct(force_can_restart: bool) -> i32 {
|
||||
}
|
||||
});
|
||||
|
||||
// so the client has started successfully
|
||||
// if this is a daemon, detach from the parent process
|
||||
if let Some(mut handle) = handle {
|
||||
handle.detach()
|
||||
}
|
||||
|
||||
// Wait for signal
|
||||
let mut lock = exit.0.lock();
|
||||
if !lock.should_exit {
|
||||
@@ -306,6 +338,11 @@ fn main_direct(force_can_restart: bool) -> i32 {
|
||||
},
|
||||
},
|
||||
Err(err) => {
|
||||
// error occured during start up
|
||||
// if this is a daemon, detach from the parent process
|
||||
if let Some(mut handle) = handle {
|
||||
handle.detach_with_msg(format!("{}", Colour::Red.paint(&err)))
|
||||
}
|
||||
writeln!(&mut stdio::stderr(), "{}", err).expect("StdErr available; qed");
|
||||
1
|
||||
},
|
||||
|
||||
@@ -488,14 +488,6 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
|
||||
|
||||
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
|
||||
|
||||
// Run in daemon mode.
|
||||
// Note, that it should be called before we leave any file descriptor open,
|
||||
// since `daemonize` will close them.
|
||||
if let Some(pid_file) = cmd.daemon {
|
||||
info!("Running as a daemon process!");
|
||||
daemonize(pid_file)?;
|
||||
}
|
||||
|
||||
// prepare account provider
|
||||
let account_provider = Arc::new(prepare_account_provider(&cmd.spec, &cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?);
|
||||
|
||||
@@ -954,23 +946,6 @@ pub fn execute<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn daemonize(pid_file: String) -> Result<(), String> {
|
||||
extern crate daemonize;
|
||||
|
||||
daemonize::Daemonize::new()
|
||||
.pid_file(pid_file)
|
||||
.chown_pid_file(true)
|
||||
.start()
|
||||
.map(|_| ())
|
||||
.map_err(|e| format!("Couldn't daemonize; {}", e))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn daemonize(_pid_file: String) -> Result<(), String> {
|
||||
Err("daemon is no supported on windows".into())
|
||||
}
|
||||
|
||||
fn print_running_environment(data_dir: &str, dirs: &Directories, db_dirs: &DatabaseDirectories) {
|
||||
info!("Starting {}", Colour::White.bold().paint(version()));
|
||||
info!("Keys path {}", Colour::White.bold().paint(dirs.keys_path(data_dir).to_string_lossy().into_owned()));
|
||||
|
||||
Reference in New Issue
Block a user