#![allow(clippy::integer_arithmetic)] pub use solana_core::test_validator; pub use solana_gossip::cluster_info::MINIMUM_VALIDATOR_PORT_RANGE_WIDTH; use { console::style, indicatif::{ProgressDrawTarget, ProgressStyle}, log::*, std::{borrow::Cow, env, fmt::Display, process::exit, thread::JoinHandle}, }; pub mod admin_rpc_service; pub mod dashboard; #[cfg(unix)] fn redirect_stderr(filename: &str) { use std::{fs::OpenOptions, os::unix::io::AsRawFd}; match OpenOptions::new() .write(true) .create(true) .append(true) .open(filename) { Ok(file) => unsafe { libc::dup2(file.as_raw_fd(), libc::STDERR_FILENO); }, Err(err) => eprintln!("Unable to open {}: {}", filename, err), } } // Redirect stderr to a file with support for logrotate by sending a SIGUSR1 to the process. // // Upon success, future `log` macros and `eprintln!()` can be found in the specified log file. pub fn redirect_stderr_to_file(logfile: Option) -> Option> { // Default to RUST_BACKTRACE=1 for more informative validator logs if env::var_os("RUST_BACKTRACE").is_none() { env::set_var("RUST_BACKTRACE", "1") } let logger_thread = match logfile { None => None, Some(logfile) => { #[cfg(unix)] { let signals = signal_hook::iterator::Signals::new(&[signal_hook::SIGUSR1]) .unwrap_or_else(|err| { eprintln!("Unable to register SIGUSR1 handler: {:?}", err); exit(1); }); redirect_stderr(&logfile); Some(std::thread::spawn(move || { for signal in signals.forever() { info!( "received SIGUSR1 ({}), reopening log file: {:?}", signal, logfile ); redirect_stderr(&logfile); } })) } #[cfg(not(unix))] { println!("logging to a file is not supported on this platform"); () } } }; solana_logger::setup_with_default("solana=info"); logger_thread } pub fn port_validator(port: String) -> Result<(), String> { port.parse::() .map(|_| ()) .map_err(|e| format!("{:?}", e)) } pub fn port_range_validator(port_range: String) -> Result<(), String> { if let Some((start, end)) = solana_net_utils::parse_port_range(&port_range) { if end - start < MINIMUM_VALIDATOR_PORT_RANGE_WIDTH { Err(format!( "Port range is too small. Try --dynamic-port-range {}-{}", start, start + MINIMUM_VALIDATOR_PORT_RANGE_WIDTH )) } else { Ok(()) } } else { Err("Invalid port range".to_string()) } } /// Pretty print a "name value" pub fn println_name_value(name: &str, value: &str) { println!("{} {}", style(name).bold(), value); } /// Creates a new process bar for processing that will take an unknown amount of time pub fn new_spinner_progress_bar() -> ProgressBar { let progress_bar = indicatif::ProgressBar::new(42); progress_bar.set_draw_target(ProgressDrawTarget::stdout()); progress_bar .set_style(ProgressStyle::default_spinner().template("{spinner:.green} {wide_msg}")); progress_bar.enable_steady_tick(100); ProgressBar { progress_bar, is_term: console::Term::stdout().is_term(), } } pub struct ProgressBar { progress_bar: indicatif::ProgressBar, is_term: bool, } impl ProgressBar { pub fn set_message> + Display>(&self, msg: T) { if self.is_term { self.progress_bar.set_message(msg); } else { println!("{}", msg); } } pub fn abandon_with_message> + Display>(&self, msg: T) { if self.is_term { self.progress_bar.abandon_with_message(msg); } else { println!("{}", msg); } } }