mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-04-20 16:06:00 -04:00
feat: extract logs logic into function and add logs command to cli
This commit is contained in:
parent
dd93a79d87
commit
f29f62a045
@ -1,6 +1,7 @@
|
||||
use crate::api::Context;
|
||||
use crate::bitcoin::{Amount, ExpiredTimelocks, TxLock};
|
||||
use crate::cli::{list_sellers, EventLoop, SellerStatus};
|
||||
use crate::common::print_or_write_logs;
|
||||
use crate::libp2p_ext::MultiAddrExt;
|
||||
use crate::network::quote::{BidQuote, ZeroQuoteReceived};
|
||||
use crate::network::swarm;
|
||||
@ -16,6 +17,7 @@ use std::cmp::min;
|
||||
use std::convert::TryInto;
|
||||
use std::future::Future;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tracing::{debug_span, field, Instrument, Span};
|
||||
@ -45,6 +47,12 @@ pub enum Method {
|
||||
swap_id: Uuid,
|
||||
},
|
||||
History,
|
||||
Logs {
|
||||
logs_dir: Option<PathBuf>,
|
||||
output_path: Option<PathBuf>,
|
||||
redact: bool,
|
||||
swap_id: Option<Uuid>
|
||||
},
|
||||
Config,
|
||||
WithdrawBtc {
|
||||
amount: Option<Amount>,
|
||||
@ -122,6 +130,13 @@ impl Method {
|
||||
log_reference_id = field::Empty
|
||||
)
|
||||
}
|
||||
Method::Logs { .. } => {
|
||||
debug_span!(
|
||||
"method",
|
||||
method_name = "Logs",
|
||||
log_reference_id = field::Empty
|
||||
)
|
||||
}
|
||||
Method::ListSellers { .. } => {
|
||||
debug_span!(
|
||||
"method",
|
||||
@ -647,6 +662,11 @@ impl Request {
|
||||
|
||||
Ok(json!({ "swaps": vec }))
|
||||
}
|
||||
Method::Logs { logs_dir, output_path, redact, swap_id } => {
|
||||
print_or_write_logs(logs_dir, output_path, swap_id, redact).await?;
|
||||
|
||||
Ok(json!({ "success": true }))
|
||||
}
|
||||
Method::GetRawStates => {
|
||||
let raw_history = context.db.raw_all().await?;
|
||||
|
||||
|
@ -20,10 +20,9 @@ use libp2p::swarm::AddressScore;
|
||||
use libp2p::Swarm;
|
||||
use swap::common::tracing_util::Format;
|
||||
use std::convert::TryInto;
|
||||
use std::fs::read_dir;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::sync::Arc;
|
||||
use std::{env, io};
|
||||
use std::env;
|
||||
use structopt::clap;
|
||||
use structopt::clap::ErrorKind;
|
||||
use swap::asb::command::{parse_args, Arguments, Command};
|
||||
@ -31,7 +30,7 @@ use swap::asb::config::{
|
||||
initial_setup, query_user_for_initial_config, read_config, Config, ConfigNotInitialized,
|
||||
};
|
||||
use swap::asb::{cancel, punish, redeem, refund, safely_abort, EventLoop, Finality, KrakenRate};
|
||||
use swap::common::{self, check_latest_version};
|
||||
use swap::common::{self, check_latest_version, print_or_write_logs};
|
||||
use swap::database::{open_db, AccessMode};
|
||||
use swap::fs::system_data_dir;
|
||||
use swap::network::rendezvous::XmrBtcNamespace;
|
||||
@ -40,8 +39,6 @@ use swap::protocol::alice::{run, AliceState};
|
||||
use swap::seed::Seed;
|
||||
use swap::tor::AuthenticatedClient;
|
||||
use swap::{bitcoin, kraken, monero, tor};
|
||||
use tokio::fs::{create_dir_all, try_exists, File};
|
||||
use tokio::io::{stdout, AsyncBufReadExt, AsyncWriteExt, BufReader, Stdout};
|
||||
use tracing_subscriber::filter::LevelFilter;
|
||||
|
||||
const DEFAULT_WALLET_NAME: &str = "asb-wallet";
|
||||
@ -261,94 +258,7 @@ async fn main() -> Result<()> {
|
||||
swap_id,
|
||||
redact,
|
||||
} => {
|
||||
// use provided directory of default one
|
||||
let default_dir = system_data_dir()?.join("logs");
|
||||
let logs_dir = logs_dir.unwrap_or(default_dir);
|
||||
|
||||
tracing::info!("Reading `*.log` files from `{}`", logs_dir.display());
|
||||
|
||||
// get all files in the directory
|
||||
let log_files = read_dir(&logs_dir)?;
|
||||
|
||||
/// Enum for abstracting over output channels
|
||||
enum OutputChannel {
|
||||
File(File),
|
||||
Stdout(Stdout),
|
||||
}
|
||||
|
||||
/// Conveniance method for writing to either file or stdout
|
||||
async fn write_to_channel(
|
||||
mut channel: &mut OutputChannel,
|
||||
output: &str,
|
||||
) -> Result<(), io::Error> {
|
||||
match &mut channel {
|
||||
OutputChannel::File(file) => file.write_all(output.as_bytes()).await,
|
||||
OutputChannel::Stdout(stdout) => stdout.write_all(output.as_bytes()).await,
|
||||
}
|
||||
}
|
||||
|
||||
// check where we should write to
|
||||
let mut output_channel = match output_path {
|
||||
Some(path) => {
|
||||
// make sure the directory exists
|
||||
if !try_exists(&path).await? {
|
||||
let mut dir_part = path.clone();
|
||||
dir_part.pop();
|
||||
create_dir_all(&dir_part).await?;
|
||||
}
|
||||
|
||||
tracing::info!("Writing logs to `{}`", path.display());
|
||||
|
||||
// create/open and truncate file.
|
||||
// this means we aren't appending which is probably intuitive behaviour
|
||||
// since we reprint the complete logs anyway
|
||||
OutputChannel::File(File::create(&path).await?)
|
||||
}
|
||||
None => OutputChannel::Stdout(stdout()),
|
||||
};
|
||||
|
||||
// conveniance method for checking whether we should filter a specific line
|
||||
let filter_by_swap_id: Box<dyn Fn(&str) -> bool> = match swap_id {
|
||||
// if we should filter by swap id, check if the line contains the string
|
||||
Some(swap_id) => {
|
||||
let swap_id = swap_id.to_string();
|
||||
Box::new(move |line: &str| line.contains(&swap_id))
|
||||
}
|
||||
// otherwise we let every line pass
|
||||
None => Box::new(|_| true),
|
||||
};
|
||||
|
||||
// print all lines from every log file. TODO: sort files by date?
|
||||
for entry in log_files {
|
||||
// get the file path
|
||||
let file_path = entry?.path();
|
||||
|
||||
// filter for .log files
|
||||
let file_name = file_path
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.unwrap_or("");
|
||||
|
||||
if !file_name.ends_with(".log") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let buf_reader = BufReader::new(File::open(&file_path).await?);
|
||||
let mut lines = buf_reader.lines();
|
||||
|
||||
// print each line, redacted if the flag is set
|
||||
while let Some(line) = lines.next_line().await? {
|
||||
// check if we should filter this line
|
||||
if !filter_by_swap_id(&line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let line = if redact { common::redact(&line) } else { line };
|
||||
write_to_channel(&mut output_channel, &line).await?;
|
||||
// don't forget newlines
|
||||
write_to_channel(&mut output_channel, "\n").await?;
|
||||
}
|
||||
}
|
||||
print_or_write_logs(logs_dir, output_path, swap_id, redact).await?;
|
||||
}
|
||||
Command::WithdrawBtc { amount, address } => {
|
||||
let bitcoin_wallet = init_bitcoin_wallet(&config, &seed, env_config).await?;
|
||||
|
@ -103,6 +103,17 @@ where
|
||||
Context::build(None, None, None, data, is_testnet, debug, json, None).await?;
|
||||
(context, request)
|
||||
}
|
||||
CliCommand::Logs {
|
||||
logs_dir,
|
||||
output_path,
|
||||
redact,
|
||||
swap_id
|
||||
} => {
|
||||
let request = Request::new(Method::Logs { logs_dir, output_path, redact, swap_id });
|
||||
let context = Context::build(None, None, None, data, is_testnet, debug, json, None).await?;
|
||||
|
||||
(context, request)
|
||||
}
|
||||
CliCommand::Config => {
|
||||
let request = Request::new(Method::Config);
|
||||
|
||||
@ -321,6 +332,30 @@ enum CliCommand {
|
||||
},
|
||||
/// Show a list of past, ongoing and completed swaps
|
||||
History,
|
||||
/// Output all logging messages that have been issued.
|
||||
Logs {
|
||||
#[structopt(
|
||||
short = "d",
|
||||
help = "Print the logs from this directory instead of the default one."
|
||||
)]
|
||||
logs_dir: Option<PathBuf>,
|
||||
#[structopt(
|
||||
short = "o",
|
||||
help = "Print the logs into this file instead of the terminal."
|
||||
)]
|
||||
output_path: Option<PathBuf>,
|
||||
#[structopt(
|
||||
help = "Redact swap-ids, Bitcoin and Monero addresses.",
|
||||
long = "redact"
|
||||
)]
|
||||
redact: bool,
|
||||
#[structopt(
|
||||
long = "swap-id",
|
||||
help = "Filter for logs concerning this swap.",
|
||||
long_help = "This checks whether each logging message contains the swap id. Some messages might be skipped when they don't contain the swap id even though they're relevant.",
|
||||
)]
|
||||
swap_id: Option<Uuid>
|
||||
},
|
||||
#[structopt(about = "Prints the current config")]
|
||||
Config,
|
||||
#[structopt(about = "Allows withdrawing BTC from the internal Bitcoin wallet.")]
|
||||
|
@ -1,8 +1,12 @@
|
||||
pub mod tracing_util;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use tokio::{fs::{create_dir_all, read_dir, try_exists, File}, io::{self, stdout, AsyncBufReadExt, AsyncWriteExt, BufReader, Stdout}};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::fs::system_data_dir;
|
||||
|
||||
const LATEST_RELEASE_URL: &str = "https://github.com/comit-network/xmr-btc-swap/releases/latest";
|
||||
|
||||
@ -64,6 +68,103 @@ macro_rules! regex_find_placeholders {
|
||||
}};
|
||||
}
|
||||
|
||||
/// Print the logs from the specified logs or from the default location
|
||||
/// to the specified path or the terminal.
|
||||
///
|
||||
/// If specified, filter by swap id or redact addresses.
|
||||
pub async fn print_or_write_logs(logs_dir: Option<PathBuf>, output_path: Option<PathBuf>, swap_id: Option<Uuid>, redact_addresses: bool) -> anyhow::Result<()> {
|
||||
// use provided directory of default one
|
||||
let default_dir = system_data_dir()?.join("logs");
|
||||
let logs_dir = logs_dir.unwrap_or(default_dir);
|
||||
|
||||
tracing::info!("Reading `*.log` files from `{}`", logs_dir.display());
|
||||
|
||||
// get all files in the directory
|
||||
let mut log_files = read_dir(&logs_dir).await?;
|
||||
|
||||
/// Enum for abstracting over output channels
|
||||
enum OutputChannel {
|
||||
File(File),
|
||||
Stdout(Stdout),
|
||||
}
|
||||
|
||||
/// Conveniance method for writing to either file or stdout
|
||||
async fn write_to_channel(
|
||||
mut channel: &mut OutputChannel,
|
||||
output: &str,
|
||||
) -> Result<(), io::Error> {
|
||||
match &mut channel {
|
||||
OutputChannel::File(file) => file.write_all(output.as_bytes()).await,
|
||||
OutputChannel::Stdout(stdout) => stdout.write_all(output.as_bytes()).await,
|
||||
}
|
||||
}
|
||||
|
||||
// check where we should write to
|
||||
let mut output_channel = match output_path {
|
||||
Some(path) => {
|
||||
// make sure the directory exists
|
||||
if !try_exists(&path).await? {
|
||||
let mut dir_part = path.clone();
|
||||
dir_part.pop();
|
||||
create_dir_all(&dir_part).await?;
|
||||
}
|
||||
|
||||
tracing::info!("Writing logs to `{}`", path.display());
|
||||
|
||||
// create/open and truncate file.
|
||||
// this means we aren't appending which is probably intuitive behaviour
|
||||
// since we reprint the complete logs anyway
|
||||
OutputChannel::File(File::create(&path).await?)
|
||||
}
|
||||
None => OutputChannel::Stdout(stdout()),
|
||||
};
|
||||
|
||||
// conveniance method for checking whether we should filter a specific line
|
||||
let filter_by_swap_id: Box<dyn Fn(&str) -> bool + Send + Sync> = match swap_id {
|
||||
// if we should filter by swap id, check if the line contains the string
|
||||
Some(swap_id) => {
|
||||
let swap_id = swap_id.to_string();
|
||||
Box::new(move |line: &str| line.contains(&swap_id))
|
||||
}
|
||||
// otherwise we let every line pass
|
||||
None => Box::new(|_| true),
|
||||
};
|
||||
|
||||
// print all lines from every log file. TODO: sort files by date?
|
||||
while let Some(entry) = log_files.next_entry().await? {
|
||||
// get the file path
|
||||
let file_path = entry.path();
|
||||
|
||||
// filter for .log files
|
||||
let file_name = file_path
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.unwrap_or("");
|
||||
|
||||
if !file_name.ends_with(".log") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let buf_reader = BufReader::new(File::open(&file_path).await?);
|
||||
let mut lines = buf_reader.lines();
|
||||
|
||||
// print each line, redacted if the flag is set
|
||||
while let Some(line) = lines.next_line().await? {
|
||||
// check if we should filter this line
|
||||
if !filter_by_swap_id(&line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let line = if redact_addresses { redact(&line) } else { line };
|
||||
write_to_channel(&mut output_channel, &line).await?;
|
||||
// don't forget newlines
|
||||
write_to_channel(&mut output_channel, "\n").await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Redact logs, etc. by replacing Bitcoin and Monero addresses
|
||||
/// with generic placeholders.
|
||||
///
|
||||
|
Loading…
x
Reference in New Issue
Block a user