Merge pull request #414 from sigp/cli-logging-2

Add CLI Flag for logging to JSON file
This commit is contained in:
Kirk Baird 2019-07-10 11:45:31 +10:00 committed by GitHub
commit e66ef32a9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 129 additions and 26 deletions

View File

@ -14,13 +14,20 @@ fn main() {
let decorator = slog_term::TermDecorator::new().build(); let decorator = slog_term::TermDecorator::new().build();
let drain = slog_term::CompactFormat::new(decorator).build().fuse(); let drain = slog_term::CompactFormat::new(decorator).build().fuse();
let drain = slog_async::Async::new(drain).build().fuse(); let drain = slog_async::Async::new(drain).build().fuse();
let log = slog::Logger::root(drain, o!()); let mut log = slog::Logger::root(drain, o!());
// CLI // CLI
let matches = App::new("Lighthouse Accounts Manager") let matches = App::new("Lighthouse Accounts Manager")
.version("0.0.1") .version("0.0.1")
.author("Sigma Prime <contact@sigmaprime.io>") .author("Sigma Prime <contact@sigmaprime.io>")
.about("Eth 2.0 Accounts Manager") .about("Eth 2.0 Accounts Manager")
.arg(
Arg::with_name("logfile")
.long("logfile")
.value_name("logfile")
.help("File path where output will be written.")
.takes_value(true),
)
.arg( .arg(
Arg::with_name("datadir") Arg::with_name("datadir")
.long("datadir") .long("datadir")
@ -91,21 +98,12 @@ fn main() {
let mut client_config = ValidatorClientConfig::default(); let mut client_config = ValidatorClientConfig::default();
if let Err(e) = client_config.apply_cli_args(&matches) {
crit!(log, "Failed to apply CLI args"; "error" => format!("{:?}", e));
return;
};
// Ensure the `data_dir` in the config matches that supplied to the CLI. // Ensure the `data_dir` in the config matches that supplied to the CLI.
client_config.data_dir = data_dir.clone(); client_config.data_dir = data_dir.clone();
// Update the client config with any CLI args. if let Err(e) = client_config.apply_cli_args(&matches, &mut log) {
match client_config.apply_cli_args(&matches) { crit!(log, "Failed to parse ClientConfig CLI arguments"; "error" => format!("{:?}", e));
Ok(()) => (),
Err(s) => {
crit!(log, "Failed to parse ClientConfig CLI arguments"; "error" => s);
return; return;
}
}; };
// Log configuration // Log configuration

View File

@ -21,8 +21,9 @@ serde_derive = "1.0"
error-chain = "0.12.0" error-chain = "0.12.0"
eth2_ssz = { path = "../../eth2/utils/ssz" } eth2_ssz = { path = "../../eth2/utils/ssz" }
slog = { version = "^2.2.3" , features = ["max_level_trace", "release_max_level_debug"] } slog = { version = "^2.2.3" , features = ["max_level_trace", "release_max_level_debug"] }
slog-term = "^2.4.0"
slog-async = "^2.3.0" slog-async = "^2.3.0"
slog-json = "^2.3"
slog-term = "^2.4.0"
tokio = "0.1.15" tokio = "0.1.15"
clap = "2.32.0" clap = "2.32.0"
dirs = "1.0.3" dirs = "1.0.3"

View File

@ -2,8 +2,10 @@ use clap::ArgMatches;
use http_server::HttpServerConfig; use http_server::HttpServerConfig;
use network::NetworkConfig; use network::NetworkConfig;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fs; use slog::{info, o, Drain};
use std::fs::{self, OpenOptions};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Mutex;
/// The core configuration of a Lighthouse beacon node. /// The core configuration of a Lighthouse beacon node.
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -11,6 +13,7 @@ pub struct Config {
pub data_dir: PathBuf, pub data_dir: PathBuf,
pub db_type: String, pub db_type: String,
db_name: String, db_name: String,
pub log_file: PathBuf,
pub network: network::NetworkConfig, pub network: network::NetworkConfig,
pub rpc: rpc::RPCConfig, pub rpc: rpc::RPCConfig,
pub http: HttpServerConfig, pub http: HttpServerConfig,
@ -20,6 +23,7 @@ impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
data_dir: PathBuf::from(".lighthouse"), data_dir: PathBuf::from(".lighthouse"),
log_file: PathBuf::from(""),
db_type: "disk".to_string(), db_type: "disk".to_string(),
db_name: "chain_db".to_string(), db_name: "chain_db".to_string(),
// Note: there are no default bootnodes specified. // Note: there are no default bootnodes specified.
@ -45,23 +49,64 @@ impl Config {
Some(path) Some(path)
} }
// Update the logger to output in JSON to specified file
fn update_logger(&mut self, log: &mut slog::Logger) -> Result<(), &'static str> {
let file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(&self.log_file);
if file.is_err() {
return Err("Cannot open log file");
}
let file = file.unwrap();
if let Some(file) = self.log_file.to_str() {
info!(
*log,
"Log file specified, output will now be written to {} in json.", file
);
} else {
info!(
*log,
"Log file specified output will now be written in json"
);
}
let drain = Mutex::new(slog_json::Json::default(file)).fuse();
let drain = slog_async::Async::new(drain).build().fuse();
*log = slog::Logger::root(drain, o!());
Ok(())
}
/// Apply the following arguments to `self`, replacing values if they are specified in `args`. /// Apply the following arguments to `self`, replacing values if they are specified in `args`.
/// ///
/// Returns an error if arguments are obviously invalid. May succeed even if some values are /// Returns an error if arguments are obviously invalid. May succeed even if some values are
/// invalid. /// invalid.
pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), String> { pub fn apply_cli_args(
&mut self,
args: &ArgMatches,
log: &mut slog::Logger,
) -> Result<(), String> {
if let Some(dir) = args.value_of("datadir") { if let Some(dir) = args.value_of("datadir") {
self.data_dir = PathBuf::from(dir); self.data_dir = PathBuf::from(dir);
}; };
if let Some(dir) = args.value_of("db") { if let Some(dir) = args.value_of("db") {
self.db_type = dir.to_string(); self.db_type = dir.to_string();
} };
self.network.apply_cli_args(args)?; self.network.apply_cli_args(args)?;
self.rpc.apply_cli_args(args)?; self.rpc.apply_cli_args(args)?;
self.http.apply_cli_args(args)?; self.http.apply_cli_args(args)?;
if let Some(log_file) = args.value_of("logfile") {
self.log_file = PathBuf::from(log_file);
self.update_logger(log)?;
};
Ok(()) Ok(())
} }
} }

View File

@ -29,6 +29,13 @@ fn main() {
.help("Data directory for keys and databases.") .help("Data directory for keys and databases.")
.takes_value(true) .takes_value(true)
) )
.arg(
Arg::with_name("logfile")
.long("logfile")
.value_name("logfile")
.help("File path where output will be written.")
.takes_value(true),
)
// network related arguments // network related arguments
.arg( .arg(
Arg::with_name("listen-address") Arg::with_name("listen-address")
@ -159,7 +166,7 @@ fn main() {
_ => drain.filter_level(Level::Info), _ => drain.filter_level(Level::Info),
}; };
let log = slog::Logger::root(drain.fuse(), o!()); let mut log = slog::Logger::root(drain.fuse(), o!());
let data_dir = match matches let data_dir = match matches
.value_of("datadir") .value_of("datadir")
@ -214,7 +221,7 @@ fn main() {
client_config.data_dir = data_dir.clone(); client_config.data_dir = data_dir.clone();
// Update the client config with any CLI args. // Update the client config with any CLI args.
match client_config.apply_cli_args(&matches) { match client_config.apply_cli_args(&matches, &mut log) {
Ok(()) => (), Ok(()) => (),
Err(s) => { Err(s) => {
crit!(log, "Failed to parse ClientConfig CLI arguments"; "error" => s); crit!(log, "Failed to parse ClientConfig CLI arguments"; "error" => s);

View File

@ -26,8 +26,9 @@ types = { path = "../eth2/types" }
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
slog = "^2.2.3" slog = "^2.2.3"
slog-term = "^2.4.0"
slog-async = "^2.3.0" slog-async = "^2.3.0"
slog-json = "^2.3"
slog-term = "^2.4.0"
tokio = "0.1.18" tokio = "0.1.18"
tokio-timer = "0.2.10" tokio-timer = "0.2.10"
toml = "^0.5" toml = "^0.5"

View File

@ -2,11 +2,11 @@ use bincode;
use bls::Keypair; use bls::Keypair;
use clap::ArgMatches; use clap::ArgMatches;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use slog::{debug, error, info}; use slog::{debug, error, info, o, Drain};
use std::fs; use std::fs::{self, File, OpenOptions};
use std::fs::File;
use std::io::{Error, ErrorKind}; use std::io::{Error, ErrorKind};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Mutex;
use types::{EthSpec, MainnetEthSpec}; use types::{EthSpec, MainnetEthSpec};
/// Stores the core configuration for this validator instance. /// Stores the core configuration for this validator instance.
@ -14,6 +14,8 @@ use types::{EthSpec, MainnetEthSpec};
pub struct Config { pub struct Config {
/// The data directory, which stores all validator databases /// The data directory, which stores all validator databases
pub data_dir: PathBuf, pub data_dir: PathBuf,
/// The path where the logs will be outputted
pub log_file: PathBuf,
/// The server at which the Beacon Node can be contacted /// The server at which the Beacon Node can be contacted
pub server: String, pub server: String,
/// The number of slots per epoch. /// The number of slots per epoch.
@ -27,6 +29,7 @@ impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
data_dir: PathBuf::from(".lighthouse-validator"), data_dir: PathBuf::from(".lighthouse-validator"),
log_file: PathBuf::from(""),
server: "localhost:5051".to_string(), server: "localhost:5051".to_string(),
slots_per_epoch: MainnetEthSpec::slots_per_epoch(), slots_per_epoch: MainnetEthSpec::slots_per_epoch(),
} }
@ -38,11 +41,20 @@ impl Config {
/// ///
/// Returns an error if arguments are obviously invalid. May succeed even if some values are /// Returns an error if arguments are obviously invalid. May succeed even if some values are
/// invalid. /// invalid.
pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), &'static str> { pub fn apply_cli_args(
&mut self,
args: &ArgMatches,
log: &mut slog::Logger,
) -> Result<(), &'static str> {
if let Some(datadir) = args.value_of("datadir") { if let Some(datadir) = args.value_of("datadir") {
self.data_dir = PathBuf::from(datadir); self.data_dir = PathBuf::from(datadir);
}; };
if let Some(log_file) = args.value_of("logfile") {
self.log_file = PathBuf::from(log_file);
self.update_logger(log)?;
};
if let Some(srv) = args.value_of("server") { if let Some(srv) = args.value_of("server") {
self.server = srv.to_string(); self.server = srv.to_string();
}; };
@ -50,6 +62,38 @@ impl Config {
Ok(()) Ok(())
} }
// Update the logger to output in JSON to specified file
fn update_logger(&mut self, log: &mut slog::Logger) -> Result<(), &'static str> {
let file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(&self.log_file);
if file.is_err() {
return Err("Cannot open log file");
}
let file = file.unwrap();
if let Some(file) = self.log_file.to_str() {
info!(
*log,
"Log file specified, output will now be written to {} in json.", file
);
} else {
info!(
*log,
"Log file specified output will now be written in json"
);
}
let drain = Mutex::new(slog_json::Json::default(file)).fuse();
let drain = slog_async::Async::new(drain).build().fuse();
*log = slog::Logger::root(drain, o!());
Ok(())
}
/// Try to load keys from validator_dir, returning None if none are found or an error. /// Try to load keys from validator_dir, returning None if none are found or an error.
#[allow(dead_code)] #[allow(dead_code)]
pub fn fetch_keys(&self, log: &slog::Logger) -> Option<Vec<Keypair>> { pub fn fetch_keys(&self, log: &slog::Logger) -> Option<Vec<Keypair>> {

View File

@ -26,7 +26,7 @@ fn main() {
let decorator = slog_term::TermDecorator::new().build(); let decorator = slog_term::TermDecorator::new().build();
let drain = slog_term::CompactFormat::new(decorator).build().fuse(); let drain = slog_term::CompactFormat::new(decorator).build().fuse();
let drain = slog_async::Async::new(drain).build().fuse(); let drain = slog_async::Async::new(drain).build().fuse();
let log = slog::Logger::root(drain, o!()); let mut log = slog::Logger::root(drain, o!());
// CLI // CLI
let matches = App::new("Lighthouse Validator Client") let matches = App::new("Lighthouse Validator Client")
@ -41,6 +41,13 @@ fn main() {
.help("Data directory for keys and databases.") .help("Data directory for keys and databases.")
.takes_value(true), .takes_value(true),
) )
.arg(
Arg::with_name("logfile")
.long("logfile")
.value_name("logfile")
.help("File path where output will be written.")
.takes_value(true),
)
.arg( .arg(
Arg::with_name("eth2-spec") Arg::with_name("eth2-spec")
.long("eth2-spec") .long("eth2-spec")
@ -123,7 +130,7 @@ fn main() {
client_config.data_dir = data_dir.clone(); client_config.data_dir = data_dir.clone();
// Update the client config with any CLI args. // Update the client config with any CLI args.
match client_config.apply_cli_args(&matches) { match client_config.apply_cli_args(&matches, &mut log) {
Ok(()) => (), Ok(()) => (),
Err(s) => { Err(s) => {
crit!(log, "Failed to parse ClientConfig CLI arguments"; "error" => s); crit!(log, "Failed to parse ClientConfig CLI arguments"; "error" => s);