Implement json output for solana ping (backport #22959) (#22968)

* Implement json output for solana ping (#22959)

(cherry picked from commit d2c89213ff)

# Conflicts:
#	cli/src/cluster_query.rs

* Fix conflicts

Co-authored-by: Tyera Eulberg <tyera@solana.com>
This commit is contained in:
mergify[bot]
2022-02-05 23:42:33 +00:00
committed by GitHub
parent c3890ada8e
commit 85856a73aa
2 changed files with 248 additions and 65 deletions

View File

@ -46,6 +46,8 @@ use {
},
};
static CHECK_MARK: Emoji = Emoji("", "");
static CROSS_MARK: Emoji = Emoji("", "");
static WARNING: Emoji = Emoji("⚠️", "!");
#[derive(PartialEq, Debug)]
@ -2523,6 +2525,172 @@ impl fmt::Display for CliGossipNodes {
impl QuietDisplay for CliGossipNodes {}
impl VerboseDisplay for CliGossipNodes {}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliPing {
pub source_pubkey: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub fixed_blockhash: Option<String>,
#[serde(skip_serializing)]
pub blockhash_from_cluster: bool,
pub pings: Vec<CliPingData>,
pub transaction_stats: CliPingTxStats,
#[serde(skip_serializing_if = "Option::is_none")]
pub confirmation_stats: Option<CliPingConfirmationStats>,
}
impl fmt::Display for CliPing {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f)?;
writeln_name_value(f, "Source Account:", &self.source_pubkey)?;
if let Some(fixed_blockhash) = &self.fixed_blockhash {
let blockhash_origin = if self.blockhash_from_cluster {
"fetched from cluster"
} else {
"supplied from cli arguments"
};
writeln!(
f,
"Fixed blockhash is used: {} ({})",
fixed_blockhash, blockhash_origin
)?;
}
writeln!(f)?;
for ping in &self.pings {
write!(f, "{}", ping)?;
}
writeln!(f)?;
writeln!(f, "--- transaction statistics ---")?;
write!(f, "{}", self.transaction_stats)?;
if let Some(confirmation_stats) = &self.confirmation_stats {
write!(f, "{}", confirmation_stats)?;
}
Ok(())
}
}
impl QuietDisplay for CliPing {}
impl VerboseDisplay for CliPing {}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliPingData {
pub success: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub signature: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(skip_serializing)]
pub print_timestamp: bool,
pub timestamp: String,
pub sequence: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub lamports: Option<u64>,
}
impl fmt::Display for CliPingData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (mark, msg) = if let Some(signature) = &self.signature {
if self.success {
(
CHECK_MARK,
format!(
"{} lamport(s) transferred: seq={:<3} time={:>4}ms signature={}",
self.lamports.unwrap(),
self.sequence,
self.ms.unwrap(),
signature
),
)
} else if let Some(error) = &self.error {
(
CROSS_MARK,
format!(
"Transaction failed: seq={:<3} error={:?} signature={}",
self.sequence, error, signature
),
)
} else {
(
CROSS_MARK,
format!(
"Confirmation timeout: seq={:<3} signature={}",
self.sequence, signature
),
)
}
} else {
(
CROSS_MARK,
format!(
"Submit failed: seq={:<3} error={:?}",
self.sequence,
self.error.as_ref().unwrap(),
),
)
};
writeln!(
f,
"{}{}{}",
if self.print_timestamp {
&self.timestamp
} else {
""
},
mark,
msg
)
}
}
impl QuietDisplay for CliPingData {}
impl VerboseDisplay for CliPingData {}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliPingTxStats {
pub num_transactions: u32,
pub num_transaction_confirmed: u32,
}
impl fmt::Display for CliPingTxStats {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
f,
"{} transactions submitted, {} transactions confirmed, {:.1}% transaction loss",
self.num_transactions,
self.num_transaction_confirmed,
(100.
- f64::from(self.num_transaction_confirmed) / f64::from(self.num_transactions)
* 100.)
)
}
}
impl QuietDisplay for CliPingTxStats {}
impl VerboseDisplay for CliPingTxStats {}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliPingConfirmationStats {
pub min: f64,
pub mean: f64,
pub max: f64,
pub std_dev: f64,
}
impl fmt::Display for CliPingConfirmationStats {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(
f,
"confirmation min/mean/max/stddev = {:.0}/{:.0}/{:.0}/{:.0} ms",
self.min, self.mean, self.max, self.std_dev,
)
}
}
impl QuietDisplay for CliPingConfirmationStats {}
impl VerboseDisplay for CliPingConfirmationStats {}
#[cfg(test)]
mod tests {
use {