Introduce --json flag for the CLI

When `--json` is used the CLI does not log to file, but only on the command line in json output.
This commit is contained in:
Daniel Karzel 2021-05-20 16:36:01 +10:00
parent 9ff29ae491
commit 0187d9ef4f
No known key found for this signature in database
GPG Key ID: 30C3FC2E438ADB6E
3 changed files with 132 additions and 21 deletions

View File

@ -45,6 +45,7 @@ async fn main() -> Result<()> {
env_config,
data_dir,
debug,
json,
cmd,
} = match parse_args_and_apply_defaults(env::args_os()) {
Ok(args) => args,
@ -76,7 +77,7 @@ async fn main() -> Result<()> {
} => {
let swap_id = Uuid::new_v4();
cli::tracing::init(debug, data_dir.join("logs"), swap_id)?;
cli::tracing::init(debug, json, data_dir.join("logs"), swap_id)?;
let db = Database::open(data_dir.join("database").as_path())
.context("Failed to open database")?;
let seed = Seed::from_file_or_generate(data_dir.as_path())
@ -167,7 +168,7 @@ async fn main() -> Result<()> {
monero_daemon_address,
tor_socks5_port,
} => {
cli::tracing::init(debug, data_dir.join("logs"), swap_id)?;
cli::tracing::init(debug, json, data_dir.join("logs"), swap_id)?;
let db = Database::open(data_dir.join("database").as_path())
.context("Failed to open database")?;
let seed = Seed::from_file_or_generate(data_dir.as_path())
@ -232,7 +233,7 @@ async fn main() -> Result<()> {
bitcoin_electrum_rpc_url,
bitcoin_target_block,
} => {
cli::tracing::init(debug, data_dir.join("logs"), swap_id)?;
cli::tracing::init(debug, json, data_dir.join("logs"), swap_id)?;
let db = Database::open(data_dir.join("database").as_path())
.context("Failed to open database")?;
let seed = Seed::from_file_or_generate(data_dir.as_path())
@ -264,7 +265,7 @@ async fn main() -> Result<()> {
bitcoin_electrum_rpc_url,
bitcoin_target_block,
} => {
cli::tracing::init(debug, data_dir.join("logs"), swap_id)?;
cli::tracing::init(debug, json, data_dir.join("logs"), swap_id)?;
let db = Database::open(data_dir.join("database").as_path())
.context("Failed to open database")?;
let seed = Seed::from_file_or_generate(data_dir.as_path())

View File

@ -29,6 +29,7 @@ const DEFAULT_TOR_SOCKS5_PORT: &str = "9050";
pub struct Arguments {
pub env_config: env::Config,
pub debug: bool,
pub json: bool,
pub data_dir: PathBuf,
pub cmd: Command,
}
@ -42,6 +43,7 @@ where
let args = RawArguments::from_clap(&matches);
let debug = args.debug;
let json = args.json;
let is_testnet = args.testnet;
let data = args.data;
@ -63,6 +65,7 @@ where
} => Ok(Arguments {
env_config: env_config_from(is_testnet),
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::BuyXmr {
seller_peer_id,
@ -86,6 +89,7 @@ where
RawCommand::History => Ok(Arguments {
env_config: env_config_from(is_testnet),
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::History,
}),
@ -106,6 +110,7 @@ where
} => Ok(Arguments {
env_config: env_config_from(is_testnet),
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Resume {
swap_id,
@ -134,6 +139,7 @@ where
} => Ok(Arguments {
env_config: env_config_from(is_testnet),
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Cancel {
swap_id,
@ -156,6 +162,7 @@ where
} => Ok(Arguments {
env_config: env_config_from(is_testnet),
debug,
json,
data_dir: data::data_dir_from(data, is_testnet)?,
cmd: Command::Refund {
swap_id,
@ -225,6 +232,13 @@ pub struct RawArguments {
#[structopt(long, help = "Activate debug logging.")]
pub debug: bool,
#[structopt(
short,
long = "json",
help = "Changes the log messages to json vs plain-text. This can be helpful to simplify automated log analyses."
)]
pub json: bool,
#[structopt(subcommand)]
pub cmd: RawCommand,
}
@ -765,11 +779,77 @@ mod tests {
assert_eq!(args, Arguments::resume_testnet_defaults().with_debug());
}
#[test]
fn given_with_json_then_json_set() {
let raw_ars = vec![
BINARY_NAME,
"--json",
"buy-xmr",
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
assert_eq!(args, Arguments::buy_xmr_mainnet_defaults().with_json());
let raw_ars = vec![
BINARY_NAME,
"--testnet",
"--json",
"buy-xmr",
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
"--seller-peer-id",
PEER_ID,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
assert_eq!(args, Arguments::buy_xmr_testnet_defaults().with_json());
let raw_ars = vec![
BINARY_NAME,
"--json",
"resume",
"--swap-id",
SWAP_ID,
"--receive-address",
MONERO_MAINNET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
assert_eq!(args, Arguments::resume_mainnet_defaults().with_json());
let raw_ars = vec![
BINARY_NAME,
"--testnet",
"--json",
"resume",
"--swap-id",
SWAP_ID,
"--receive-address",
MONERO_STAGENET_ADDRESS,
"--seller-addr",
MUTLI_ADDRESS,
];
let args = parse_args_and_apply_defaults(raw_ars).unwrap();
assert_eq!(args, Arguments::resume_testnet_defaults().with_json());
}
impl Arguments {
pub fn buy_xmr_testnet_defaults() -> Self {
Self {
env_config: env::Testnet::get_config(),
debug: false,
json: false,
data_dir: data_dir_path_cli().join(TESTNET),
cmd: Command::BuyXmr {
seller_peer_id: PeerId::from_str(PEER_ID).unwrap(),
@ -789,6 +869,7 @@ mod tests {
Self {
env_config: env::Mainnet::get_config(),
debug: false,
json: false,
data_dir: data_dir_path_cli().join(MAINNET),
cmd: Command::BuyXmr {
seller_peer_id: PeerId::from_str(PEER_ID).unwrap(),
@ -807,6 +888,7 @@ mod tests {
Self {
env_config: env::Testnet::get_config(),
debug: false,
json: false,
data_dir: data_dir_path_cli().join(TESTNET),
cmd: Command::Resume {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
@ -826,6 +908,7 @@ mod tests {
Self {
env_config: env::Mainnet::get_config(),
debug: false,
json: false,
data_dir: data_dir_path_cli().join(MAINNET),
cmd: Command::Resume {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
@ -844,6 +927,7 @@ mod tests {
Self {
env_config: env::Testnet::get_config(),
debug: false,
json: false,
data_dir: data_dir_path_cli().join(TESTNET),
cmd: Command::Cancel {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
@ -859,6 +943,7 @@ mod tests {
Self {
env_config: env::Mainnet::get_config(),
debug: false,
json: false,
data_dir: data_dir_path_cli().join(MAINNET),
cmd: Command::Cancel {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
@ -873,6 +958,7 @@ mod tests {
Self {
env_config: env::Testnet::get_config(),
debug: false,
json: false,
data_dir: data_dir_path_cli().join(TESTNET),
cmd: Command::Refund {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
@ -888,6 +974,7 @@ mod tests {
Self {
env_config: env::Mainnet::get_config(),
debug: false,
json: false,
data_dir: data_dir_path_cli().join(MAINNET),
cmd: Command::Refund {
swap_id: Uuid::from_str(SWAP_ID).unwrap(),
@ -907,6 +994,11 @@ mod tests {
self.debug = true;
self
}
pub fn with_json(mut self) -> Self {
self.json = true;
self
}
}
fn data_dir_path_cli() -> PathBuf {

View File

@ -5,30 +5,48 @@ use tracing::{Event, Level, Subscriber};
use tracing_subscriber::fmt::format::{DefaultFields, Format};
use tracing_subscriber::fmt::time::ChronoLocal;
use tracing_subscriber::layer::{Context, SubscriberExt};
use tracing_subscriber::{fmt, EnvFilter, Layer, Registry};
use tracing_subscriber::{fmt, EnvFilter, FmtSubscriber, Layer, Registry};
use uuid::Uuid;
pub fn init(debug: bool, dir: impl AsRef<Path>, swap_id: Uuid) -> Result<()> {
let level_filter = EnvFilter::try_new("swap=debug")?;
pub fn init(debug: bool, json: bool, dir: impl AsRef<Path>, swap_id: Uuid) -> Result<()> {
if json {
let level = if debug { Level::DEBUG } else { Level::INFO };
let registry = Registry::default().with(level_filter);
let is_terminal = atty::is(atty::Stream::Stderr);
let appender = tracing_appender::rolling::never(dir, format!("swap-{}.log", swap_id));
let (appender, guard) = tracing_appender::non_blocking(appender);
FmtSubscriber::builder()
.with_env_filter(format!("swap={}", level))
.with_writer(std::io::stderr)
.with_ansi(is_terminal)
.with_timer(ChronoLocal::with_format("%F %T".to_owned()))
.with_target(false)
.json()
.init();
std::mem::forget(guard);
let file_logger = fmt::layer()
.with_ansi(false)
.with_target(false)
.with_writer(appender);
if debug {
set_global_default(registry.with(file_logger).with(debug_terminal_printer()))?;
Ok(())
} else {
set_global_default(registry.with(file_logger).with(info_terminal_printer()))?;
let level_filter = EnvFilter::try_new("swap=debug")?;
let registry = Registry::default().with(level_filter);
let appender = tracing_appender::rolling::never(dir, format!("swap-{}.log", swap_id));
let (appender, guard) = tracing_appender::non_blocking(appender);
std::mem::forget(guard);
let file_logger = fmt::layer()
.with_ansi(false)
.with_target(false)
.with_writer(appender);
if debug {
set_global_default(registry.with(file_logger).with(debug_terminal_printer()))?;
} else {
set_global_default(registry.with(file_logger).with(info_terminal_printer()))?;
}
Ok(())
}
Ok(())
}
pub struct StdErrPrinter<L> {