Add solana logs
command
This commit is contained in:
@ -31,7 +31,7 @@ use solana_client::{
|
||||
client_error::{ClientError, ClientErrorKind, Result as ClientResult},
|
||||
nonce_utils,
|
||||
rpc_client::RpcClient,
|
||||
rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig},
|
||||
rpc_config::{RpcLargestAccountsFilter, RpcSendTransactionConfig, RpcTransactionLogsFilter},
|
||||
rpc_request::MAX_GET_SIGNATURE_STATUSES_QUERY_ITEMS,
|
||||
rpc_response::{RpcKeyedAccount, RpcLeaderSchedule},
|
||||
};
|
||||
@ -120,6 +120,9 @@ pub enum CliCommand {
|
||||
},
|
||||
LeaderSchedule,
|
||||
LiveSlots,
|
||||
Logs {
|
||||
filter: RpcTransactionLogsFilter,
|
||||
},
|
||||
Ping {
|
||||
lamports: u64,
|
||||
interval: Duration,
|
||||
@ -585,6 +588,7 @@ pub fn parse_command(
|
||||
command: CliCommand::LiveSlots,
|
||||
signers: vec![],
|
||||
}),
|
||||
("logs", Some(matches)) => parse_logs(matches, wallet_manager),
|
||||
("block-production", Some(matches)) => parse_show_block_production(matches),
|
||||
("gossip", Some(_matches)) => Ok(CliCommandInfo {
|
||||
command: CliCommand::ShowGossip,
|
||||
@ -1559,7 +1563,8 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
||||
process_inflation_subcommand(&rpc_client, config, inflation_subcommand)
|
||||
}
|
||||
CliCommand::LeaderSchedule => process_leader_schedule(&rpc_client),
|
||||
CliCommand::LiveSlots => process_live_slots(&config.websocket_url),
|
||||
CliCommand::LiveSlots => process_live_slots(&config),
|
||||
CliCommand::Logs { filter } => process_logs(&config, filter),
|
||||
CliCommand::Ping {
|
||||
lamports,
|
||||
interval,
|
||||
|
@ -7,7 +7,10 @@ use chrono::{Local, TimeZone};
|
||||
use clap::{value_t, value_t_or_exit, App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||
use console::{style, Emoji};
|
||||
use solana_clap_utils::{
|
||||
commitment::commitment_arg, input_parsers::*, input_validators::*, keypair::DefaultSigner,
|
||||
commitment::{commitment_arg, commitment_arg_with_default},
|
||||
input_parsers::*,
|
||||
input_validators::*,
|
||||
keypair::DefaultSigner,
|
||||
};
|
||||
use solana_cli_output::{
|
||||
display::{
|
||||
@ -21,7 +24,7 @@ use solana_client::{
|
||||
rpc_client::{GetConfirmedSignaturesForAddress2Config, RpcClient},
|
||||
rpc_config::{
|
||||
RpcAccountInfoConfig, RpcLargestAccountsConfig, RpcLargestAccountsFilter,
|
||||
RpcProgramAccountsConfig,
|
||||
RpcProgramAccountsConfig, RpcTransactionLogsConfig, RpcTransactionLogsFilter,
|
||||
},
|
||||
rpc_filter,
|
||||
rpc_response::SlotInfo,
|
||||
@ -233,6 +236,26 @@ impl ClusterQuerySubCommands for App<'_, '_> {
|
||||
SubCommand::with_name("live-slots")
|
||||
.about("Show information about the current slot progression"),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("logs")
|
||||
.about("Stream transaction logs")
|
||||
.arg(
|
||||
pubkey!(Arg::with_name("address")
|
||||
.index(1)
|
||||
.value_name("ADDRESS"),
|
||||
"Account address to monitor \
|
||||
[default: monitor all transactions except for votes] \
|
||||
")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("include_votes")
|
||||
.long("include-votes")
|
||||
.takes_value(false)
|
||||
.conflicts_with("address")
|
||||
.help("Include vote transactions when monitoring all transactions")
|
||||
)
|
||||
.arg(commitment_arg_with_default("singleGossip")),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("block-production")
|
||||
.about("Show information about block production")
|
||||
@ -1172,24 +1195,83 @@ pub fn process_ping(
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
||||
pub fn process_live_slots(url: &str) -> ProcessResult {
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
pub fn parse_logs(
|
||||
matches: &ArgMatches<'_>,
|
||||
wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
||||
) -> Result<CliCommandInfo, CliError> {
|
||||
let address = pubkey_of_signer(matches, "address", wallet_manager)?;
|
||||
let include_votes = matches.is_present("include_votes");
|
||||
|
||||
// Disable Ctrl+C handler as sometimes the PubsubClient shutdown can stall. Also it doesn't
|
||||
// really matter that the shutdown is clean because the process is terminating.
|
||||
/*
|
||||
let exit_clone = exit.clone();
|
||||
ctrlc::set_handler(move || {
|
||||
exit_clone.store(true, Ordering::Relaxed);
|
||||
})?;
|
||||
*/
|
||||
let filter = match address {
|
||||
None => {
|
||||
if include_votes {
|
||||
RpcTransactionLogsFilter::AllWithVotes
|
||||
} else {
|
||||
RpcTransactionLogsFilter::All
|
||||
}
|
||||
}
|
||||
Some(address) => RpcTransactionLogsFilter::Mentions(vec![address.to_string()]),
|
||||
};
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::Logs { filter },
|
||||
signers: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_logs(config: &CliConfig, filter: &RpcTransactionLogsFilter) -> ProcessResult {
|
||||
println!(
|
||||
"Streaming transaction logs{}. {:?} commitment",
|
||||
match filter {
|
||||
RpcTransactionLogsFilter::All => "".into(),
|
||||
RpcTransactionLogsFilter::AllWithVotes => " (including votes)".into(),
|
||||
RpcTransactionLogsFilter::Mentions(addresses) =>
|
||||
format!(" mentioning {}", addresses.join(",")),
|
||||
},
|
||||
config.commitment.commitment
|
||||
);
|
||||
|
||||
let (_client, receiver) = PubsubClient::logs_subscribe(
|
||||
&config.websocket_url,
|
||||
filter.clone(),
|
||||
RpcTransactionLogsConfig {
|
||||
commitment: Some(config.commitment),
|
||||
},
|
||||
)?;
|
||||
|
||||
loop {
|
||||
match receiver.recv() {
|
||||
Ok(logs) => {
|
||||
println!("Transaction executed in slot {}:", logs.context.slot);
|
||||
println!(" Signature: {}", logs.value.signature);
|
||||
println!(
|
||||
" Status: {}",
|
||||
logs.value
|
||||
.err
|
||||
.map(|err| err.to_string())
|
||||
.unwrap_or_else(|| "Ok".to_string())
|
||||
);
|
||||
println!(" Log Messages:");
|
||||
for log in logs.value.logs {
|
||||
println!(" {}", log);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
return Ok(format!("Disconnected: {}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_live_slots(config: &CliConfig) -> ProcessResult {
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let mut current: Option<SlotInfo> = None;
|
||||
let mut message = "".to_string();
|
||||
|
||||
let slot_progress = new_spinner_progress_bar();
|
||||
slot_progress.set_message("Connecting...");
|
||||
let (mut client, receiver) = PubsubClient::slot_subscribe(url)?;
|
||||
let (mut client, receiver) = PubsubClient::slot_subscribe(&config.websocket_url)?;
|
||||
slot_progress.set_message("Connected.");
|
||||
|
||||
let spacer = "|";
|
||||
|
Reference in New Issue
Block a user