clean up display formatting

This commit is contained in:
Christien Rioux 2024-09-29 21:38:12 -04:00
parent dc944fe920
commit ef66ad3f8f
15 changed files with 370 additions and 332 deletions

View File

@ -143,7 +143,7 @@ impl CommandProcessor {
disable [flag] unset a flag
valid flags in include:
app_messages
Server Debug Commands:
Core Debug Commands:
{}
"#,
indent_all_by(4, out)

View File

@ -97,6 +97,7 @@ use enumset::*;
use eyre::{bail, eyre, Report as EyreReport, Result as EyreResult, WrapErr};
#[allow(unused_imports)]
use futures_util::stream::{FuturesOrdered, FuturesUnordered};
use indent::*;
use parking_lot::*;
use schemars::{schema_for, JsonSchema};
use serde::*;

View File

@ -468,12 +468,8 @@ impl NetworkConnection {
pub fn debug_print(&self, cur_ts: Timestamp) -> String {
format!(
"{} <- {} | {} | est {} sent {} rcvd {} refcount {}{}",
self.flow.remote_address(),
self.flow
.local()
.map(|x| x.to_string())
.unwrap_or("---".to_owned()),
"{} | {} | est {} sent {} rcvd {} refcount {}{}",
self.flow,
self.connection_id.as_u64(),
debug_duration(
cur_ts

View File

@ -23,7 +23,7 @@ impl NetworkManager {
let data = if let Some(flow) = destination_node_ref.last_flow() {
#[cfg(feature = "verbose-tracing")]
log_net!(debug
"send_data: trying last flow ({:?}) for {:?}",
"send_data: trying last flow ({}) for {:?}",
flow,
destination_node_ref
);
@ -35,7 +35,7 @@ impl NetworkManager {
#[cfg(feature = "verbose-tracing")]
log_net!(debug
"send_data: sent to last flow ({:?}) for {:?}",
"send_data: sent to last flow ({}) for {:?}",
unique_flow,
destination_node_ref
);
@ -51,7 +51,7 @@ impl NetworkManager {
// so pass the data back out
#[cfg(feature = "verbose-tracing")]
log_net!(debug
"send_data: did not send to last flow ({:?}) for {:?}",
"send_data: did not send to last flow ({}) for {:?}",
flow,
destination_node_ref
);

View File

@ -80,4 +80,19 @@ pub struct UniqueFlow {
pub connection_id: Option<NetworkConnectionId>,
}
impl fmt::Display for UniqueFlow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} ({})",
self.flow,
if let Some(connection_id) = &self.connection_id {
format!("id={}", connection_id)
} else {
"---".to_string()
}
)
}
}
pub type NetworkConnectionId = AlignedU64;

View File

@ -1,5 +1,3 @@
use indent::indent_by;
use super::*;
use core::sync::atomic::{AtomicU32, Ordering};
@ -96,7 +94,7 @@ pub(crate) struct LastFlowKey(pub ProtocolType, pub AddressType);
pub(crate) struct LastSenderInfoKey(pub RoutingDomain, pub ProtocolType, pub AddressType);
/// Bucket entry information specific to the LocalNetwork RoutingDomain
#[derive(Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct BucketEntryPublicInternet {
/// The PublicInternet node infoe
signed_node_info: Option<Box<SignedNodeInfo>>,
@ -106,12 +104,11 @@ pub(crate) struct BucketEntryPublicInternet {
node_status: Option<NodeStatus>,
}
impl fmt::Debug for BucketEntryPublicInternet {
impl fmt::Display for BucketEntryPublicInternet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
if let Some(sni) = &self.signed_node_info {
writeln!(f, "signed_node_info:")?;
write!(f, " {}", indent_by(4, format!("{:?}", sni)))?;
write!(f, " {}", indent_string(sni))?;
} else {
writeln!(f, "signed_node_info: None")?;
}
@ -122,21 +119,11 @@ impl fmt::Debug for BucketEntryPublicInternet {
)?;
writeln!(f, "node_status: {:?}", self.node_status)?;
Ok(())
} else {
f.debug_struct("BucketEntryPublicInternet")
.field("signed_node_info", &self.signed_node_info)
.field(
"last_seen_our_node_info_ts",
&self.last_seen_our_node_info_ts,
)
.field("node_status", &self.node_status)
.finish()
}
}
}
/// Bucket entry information specific to the LocalNetwork RoutingDomain
#[derive(Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct BucketEntryLocalNetwork {
/// The LocalNetwork node info
signed_node_info: Option<Box<SignedNodeInfo>>,
@ -146,12 +133,11 @@ pub(crate) struct BucketEntryLocalNetwork {
node_status: Option<NodeStatus>,
}
impl fmt::Debug for BucketEntryLocalNetwork {
impl fmt::Display for BucketEntryLocalNetwork {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
if let Some(sni) = &self.signed_node_info {
writeln!(f, "signed_node_info:")?;
write!(f, " {}", indent_by(4, format!("{:?}", sni)))?;
write!(f, " {}", indent_string(sni))?;
} else {
writeln!(f, "signed_node_info: None")?;
}
@ -162,21 +148,11 @@ impl fmt::Debug for BucketEntryLocalNetwork {
)?;
writeln!(f, "node_status: {:?}", self.node_status)?;
Ok(())
} else {
f.debug_struct("BucketEntryLocalNetwork")
.field("signed_node_info", &self.signed_node_info)
.field(
"last_seen_our_node_info_ts",
&self.last_seen_our_node_info_ts,
)
.field("node_status", &self.node_status)
.finish()
}
}
}
/// The data associated with each bucket entry
#[derive(Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct BucketEntryInner {
/// The node ids matching this bucket entry, with the cryptography versions supported by this node as the 'kind' field
validated_node_ids: TypedKeyGroup,
@ -227,9 +203,8 @@ pub(crate) struct BucketEntryInner {
node_ref_tracks: HashMap<usize, backtrace::Backtrace>,
}
impl fmt::Debug for BucketEntryInner {
impl fmt::Display for BucketEntryInner {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
writeln!(f, "validated_node_ids: {}", self.validated_node_ids)?;
writeln!(f, "unsupported_node_ids: {}", self.unsupported_node_ids)?;
writeln!(f, "envelope_support: {:?}", self.envelope_support)?;
@ -242,7 +217,7 @@ impl fmt::Debug for BucketEntryInner {
for lf in &self.last_flows {
writeln!(
f,
" {:?}/{:?}: {} @ {}",
" {:?}/{:?}: {} @ {:?}",
lf.0 .0, lf.0 .1, lf.1 .0, lf.1 .1
)?;
}
@ -255,19 +230,11 @@ impl fmt::Debug for BucketEntryInner {
)?;
}
writeln!(f, "public_internet:")?;
writeln!(
f,
" {}",
indent_by(4, format!("{:?}", self.public_internet))
)?;
write!(f, "{}", indent_all_string(&self.public_internet))?;
writeln!(f, "local_network:")?;
writeln!(
f,
" {}",
indent_by(4, format!("{:?}", self.local_network))
)?;
write!(f, "{}", indent_all_string(&self.local_network))?;
writeln!(f, "peer_stats:")?;
writeln!(f, " {}", indent_by(4, format!("{:?}", self.peer_stats)))?;
write!(f, "{}", indent_all_string(&self.peer_stats))?;
writeln!(
f,
"punishment: {}",
@ -279,32 +246,6 @@ impl fmt::Debug for BucketEntryInner {
)?;
Ok(())
} else {
let mut out = f.debug_struct("BucketEntryInner");
out.field("validated_node_ids", &self.validated_node_ids)
.field("unsupported_node_ids", &self.unsupported_node_ids)
.field("envelope_support", &self.envelope_support)
.field(
"updated_since_last_network_change",
&self.updated_since_last_network_change,
)
.field("last_flows", &self.last_flows)
.field("last_sender_info", &self.last_sender_info)
.field("public_internet", &self.public_internet)
.field("local_network", &self.local_network)
.field("peer_stats", &self.peer_stats)
.field("latency_stats_accounting", &self.latency_stats_accounting)
.field("transfer_stats_accounting", &self.transfer_stats_accounting)
.field("state_stats_accounting", &self.state_stats_accounting)
.field("answer_stats_accounting", &self.answer_stats_accounting)
.field("punishment", &self.punishment);
#[cfg(feature = "tracking")]
{
out = out.field("next_track_id", &self.next_track_id);
out = out.field("node_ref_tracks", &self.node_ref_tracks);
}
out.finish()
}
}
}

View File

@ -1,5 +1,4 @@
use super::*;
use indent::indent_by;
use routing_table::tasks::bootstrap::BOOTSTRAP_TXT_VERSION_0;
impl RoutingTable {
@ -67,22 +66,12 @@ impl RoutingTable {
pub(crate) fn debug_info_nodeinfo(&self) -> String {
let mut out = String::new();
let inner = self.inner.read();
out += "Routing Table Info:\n";
out += &format!("Node Ids: {}\n", self.unlocked_inner.node_ids());
out += &format!(
" Self Latency Stats Accounting: {:#?}\n\n",
inner.self_latency_stats_accounting
"Self Transfer Stats:\n{}",
indent_all_string(&inner.self_transfer_stats)
);
out += &format!(
" Self Transfer Stats Accounting: {:#?}\n\n",
inner.self_transfer_stats_accounting
);
out += &format!(
" Self Transfer Stats: {:#?}\n\n",
inner.self_transfer_stats
);
out += &format!(" Version: {}\n\n", veilid_version_string());
out += &format!("Version: {}", veilid_version_string());
out
}
@ -94,11 +83,11 @@ impl RoutingTable {
out += "Local Network Dial Info Details:\n";
for (n, ldi) in ldis.iter().enumerate() {
out += &format!(" {:>2}: {:?}\n", n, ldi);
out += &indent_all_string(&format!("{:>2}: {}\n", n, ldi));
}
out += "Public Internet Dial Info Details:\n";
for (n, gdi) in gdis.iter().enumerate() {
out += &format!(" {:>2}: {:?}\n", n, gdi);
out += &indent_all_string(&format!("{:>2}: {}\n", n, gdi));
}
out
}
@ -110,23 +99,16 @@ impl RoutingTable {
) -> String {
let mut out = String::new();
if published {
out += &format!(
"{:?} Published PeerInfo:\n {}\n",
routing_domain,
indent_by(
4,
format!("{:?}", self.get_published_peer_info(routing_domain))
)
);
let pistr = if let Some(pi) = self.get_published_peer_info(routing_domain) {
format!("\n{}\n", indent_all_string(&pi))
} else {
out += &format!(
"{:?} Current PeerInfo:\n {}\n",
routing_domain,
indent_by(
4,
format!("{:?}", self.get_current_peer_info(routing_domain))
)
);
" None".to_owned()
};
out += &format!("{:?} Published PeerInfo:{}", routing_domain, pistr);
} else {
let pi = self.get_current_peer_info(routing_domain);
let pistr = format!("\n{}\n", indent_all_string(&pi));
out += &format!("{:?} Current PeerInfo:{}", routing_domain, pistr);
}
out
}
@ -160,6 +142,46 @@ impl RoutingTable {
}
}
fn format_entry(cur_ts: Timestamp, node: TypedKey, e: &BucketEntryInner) -> String {
format!(
" {} [{}] {} [{}] lastq@{:?} seen@{:?}",
// node id
node,
// state reason
Self::format_state_reason(e.state_reason(cur_ts)),
// average latency
e.peer_stats()
.latency
.as_ref()
.map(|l| l.to_string())
.unwrap_or_else(|| "???".to_string()),
// capabilities
if let Some(ni) = e.node_info(RoutingDomain::PublicInternet) {
ni.capabilities()
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join(",")
} else {
"???".to_owned()
},
// duration since last question
e.peer_stats()
.rpc_stats
.last_question_ts
.as_ref()
.map(|l| l.to_string())
.unwrap_or_else(|| "???".to_string()),
// duration since last seen
e.peer_stats()
.rpc_stats
.last_seen_ts
.as_ref()
.map(|l| l.to_string())
.unwrap_or_else(|| "???".to_string()),
)
}
pub(crate) fn debug_info_entries(
&self,
min_state: BucketEntryState,
@ -198,35 +220,12 @@ impl RoutingTable {
if !filtered_entries.is_empty() {
out += &format!("{} Bucket #{}:\n", ck, b);
for e in filtered_entries {
let state_reason = e.1.with(inner, |_rti, e| e.state_reason(cur_ts));
out += &format!(
" {} [{}] {} [{}]\n",
e.0.encode(),
Self::format_state_reason(state_reason),
e.1.with(inner, |_rti, e| {
e.peer_stats()
.latency
.as_ref()
.map(|l| {
format!(
"{:.2}ms",
timestamp_to_secs(l.average.as_u64()) * 1000.0
)
})
.unwrap_or_else(|| "???.??ms".to_string())
}),
e.1.with(inner, |_rti, e| {
if let Some(ni) = e.node_info(RoutingDomain::PublicInternet) {
ni.capabilities()
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join(",")
} else {
"???".to_owned()
}
})
);
let node = *e.0;
out += " ";
out += &e.1.with(inner, |_rti, e| {
Self::format_entry(cur_ts, TypedKey::new(*ck, node), e)
});
out += "\n";
}
}
b += 1;
@ -266,30 +265,9 @@ impl RoutingTable {
);
let mut out = String::new();
for node in nodes {
out += &node.operate(|_rti, e| {
let state_reason = e.state_reason(cur_ts);
format!(
" {} [{}] {} [{}]\n",
node,
Self::format_state_reason(state_reason),
e.peer_stats()
.latency
.as_ref()
.map(|l| {
format!("{:.2}ms", timestamp_to_secs(l.average.as_u64()) * 1000.0)
})
.unwrap_or_else(|| "???.??ms".to_string()),
if let Some(ni) = e.node_info(RoutingDomain::PublicInternet) {
ni.capabilities()
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join(",")
} else {
"???".to_owned()
}
)
});
out += " ";
out += &node.operate(|_rti, e| Self::format_entry(cur_ts, node.best_node_id(), e));
out += "\n";
}
out
@ -302,7 +280,7 @@ impl RoutingTable {
out += &node_ref.operate(|_rti, e| {
let state_reason = e.state_reason(cur_ts);
format!(
"{:?}\nstate: {}\n",
"{}\nstate: {}\n",
e,
Self::format_state_reason(state_reason),
)

View File

@ -1,13 +1,13 @@
use super::*;
// Keep member order appropriate for sorting < preference
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Serialize, Deserialize)]
pub struct DialInfoDetail {
pub class: DialInfoClass,
pub dial_info: DialInfo,
}
impl fmt::Debug for DialInfoDetail {
impl fmt::Display for DialInfoDetail {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}:{}", self.class, self.dial_info)
}

View File

@ -15,7 +15,7 @@ pub const CAP_BLOCKSTORE: Capability = FourCC(*b"BLOC");
pub const DISTANCE_METRIC_CAPABILITIES: &[Capability] = &[CAP_DHT, CAP_DHT_WATCH];
#[derive(Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct NodeInfo {
network_class: NetworkClass,
outbound_protocols: ProtocolTypeSet,
@ -26,9 +26,8 @@ pub struct NodeInfo {
dial_info_detail_list: Vec<DialInfoDetail>,
}
impl fmt::Debug for NodeInfo {
impl fmt::Display for NodeInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
writeln!(f, "network_class: {:?}", self.network_class)?;
writeln!(f, "outbound_protocols: {:?}", self.outbound_protocols)?;
writeln!(f, "address_types: {:?}", self.address_types)?;
@ -37,20 +36,9 @@ impl fmt::Debug for NodeInfo {
writeln!(f, "capabilities: {:?}", self.capabilities)?;
writeln!(f, "dial_info_detail_list:")?;
for did in &self.dial_info_detail_list {
writeln!(f, " {:?}", did)?;
writeln!(f, " {}", did)?;
}
Ok(())
} else {
f.debug_struct("NodeInfo")
.field("network_class", &self.network_class)
.field("outbound_protocols", &self.outbound_protocols)
.field("address_types", &self.address_types)
.field("envelope_support", &self.envelope_support)
.field("crypto_support", &self.crypto_support)
.field("capabilities", &self.capabilities)
.field("dial_info_detail_list", &self.dial_info_detail_list)
.finish()
}
}
}

View File

@ -1,33 +1,19 @@
use indent::indent_by;
use super::*;
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PeerInfo {
routing_domain: RoutingDomain,
node_ids: TypedKeyGroup,
signed_node_info: SignedNodeInfo,
}
impl fmt::Debug for PeerInfo {
impl fmt::Display for PeerInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
writeln!(f, "routing_domain: {:?}", self.routing_domain)?;
writeln!(f, "node_ids: {}", self.node_ids)?;
writeln!(f, "signed_node_info:")?;
write!(
f,
" {}",
indent_by(4, format!("{:?}", self.signed_node_info))
)?;
write!(f, "{}", indent_all_string(&self.signed_node_info))?;
Ok(())
} else {
f.debug_struct("PeerInfo")
.field("routing_domain", &self.routing_domain)
.field("node_ids", &self.node_ids)
.field("signed_node_info", &self.signed_node_info)
.finish()
}
}
}

View File

@ -1,33 +1,23 @@
use indent::indent_by;
use super::*;
/// Signed NodeInfo that can be passed around amongst peers and verifiable
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SignedDirectNodeInfo {
node_info: NodeInfo,
timestamp: Timestamp,
signatures: Vec<TypedSignature>,
}
impl fmt::Debug for SignedDirectNodeInfo {
impl fmt::Display for SignedDirectNodeInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
writeln!(f, "node_info:")?;
write!(f, " {}", indent_by(4, format!("{:?}", self.node_info)))?;
writeln!(f, "timestamp: {}", self.timestamp)?;
write!(f, "{}", indent_all_string(&self.node_info))?;
writeln!(f, "timestamp: {:?}", self.timestamp)?;
writeln!(f, "signatures:")?;
for sig in &self.signatures {
writeln!(f, " {}", sig)?;
writeln!(f, "{}", indent_all_string(sig))?;
}
Ok(())
} else {
f.debug_struct("SignedDirectNodeInfo")
.field("node_info", &self.node_info)
.field("timestamp", &self.timestamp)
.field("signatures", &self.signatures)
.finish()
}
}
}

View File

@ -1,34 +1,25 @@
use indent::indent_by;
use super::*;
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum SignedNodeInfo {
Direct(SignedDirectNodeInfo),
Relayed(SignedRelayedNodeInfo),
}
impl fmt::Debug for SignedNodeInfo {
impl fmt::Display for SignedNodeInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
match self {
Self::Direct(arg0) => {
writeln!(f, "direct:")?;
write!(f, " {}", indent_by(4, format!("{:?}", arg0)))?;
write!(f, "{}", indent_all_string(arg0))?;
Ok(())
}
Self::Relayed(arg0) => {
writeln!(f, "relayed:")?;
write!(f, " {}", indent_by(4, format!("{:?}", arg0)))?;
write!(f, "{}", indent_all_string(&arg0))?;
Ok(())
}
}
} else {
match self {
Self::Direct(arg0) => f.debug_tuple("Direct").field(arg0).finish(),
Self::Relayed(arg0) => f.debug_tuple("Relayed").field(arg0).finish(),
}
}
}
}

View File

@ -1,9 +1,7 @@
use indent::indent_by;
use super::*;
/// Signed NodeInfo with a relay that can be passed around amongst peers and verifiable
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SignedRelayedNodeInfo {
node_info: NodeInfo,
relay_ids: TypedKeyGroup,
@ -12,29 +10,19 @@ pub struct SignedRelayedNodeInfo {
signatures: Vec<TypedSignature>,
}
impl fmt::Debug for SignedRelayedNodeInfo {
impl fmt::Display for SignedRelayedNodeInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !f.alternate() {
writeln!(f, "node_info:")?;
write!(f, " {}", indent_by(4, format!("{:?}", self.node_info)))?;
write!(f, "{}", indent_all_string(&self.node_info))?;
writeln!(f, "relay_ids: {}", self.relay_ids)?;
writeln!(f, "relay_info:")?;
write!(f, " {}", indent_by(4, format!("{:?}", self.relay_info)))?;
writeln!(f, "timestamp: {}", self.timestamp)?;
write!(f, "{}", indent_all_string(&self.relay_info))?;
writeln!(f, "timestamp: {:?}", self.timestamp)?;
writeln!(f, "signatures:")?;
for sig in &self.signatures {
writeln!(f, " {}", sig)?;
writeln!(f, "{}", indent_all_string(sig))?;
}
Ok(())
} else {
f.debug_struct("SignedDirectNodeInfo")
.field("node_info", &self.node_info)
.field("relay_ids", &self.relay_ids)
.field("relay_info", &self.relay_info)
.field("timestamp", &self.timestamp)
.field("signatures", &self.signatures)
.finish()
}
}
}

View File

@ -722,7 +722,7 @@ impl VeilidAPI {
// Dump connection table
let connman = connection_manager.debug_print().await;
Ok(format!("{}\n\n{}\n\n{}\n\n", nodeinfo, peertable, connman))
Ok(format!("{}\n{}\n{}\n", nodeinfo, peertable, connman))
}
async fn debug_nodeid(&self, _args: String) -> VeilidAPIResult<String> {
@ -2249,3 +2249,10 @@ TableDB Operations:
Ok((key, rc))
}
}
const DEFAULT_INDENT: usize = 4;
pub fn indent_string<S: ToString>(s: &S) -> String {
indent_by(DEFAULT_INDENT, s.to_string())
}
pub fn indent_all_string<S: ToString>(s: &S) -> String {
indent_all_by(DEFAULT_INDENT, s.to_string())
}

View File

@ -12,6 +12,17 @@ pub struct LatencyStats {
pub slowest: TimestampDuration,
}
impl fmt::Display for LatencyStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{:?} slow / {:?} avg / {:?} fast",
self.slowest, self.average, self.fastest
)?;
Ok(())
}
}
/// Measurement of how much data has transferred to or from this node over a time span
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(target_arch = "wasm32", derive(Tsify))]
@ -26,6 +37,17 @@ pub struct TransferStats {
pub minimum: ByteCount,
}
impl fmt::Display for TransferStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} min / {} avg / {} max / {} total",
self.minimum, self.average, self.maximum, self.total
)?;
Ok(())
}
}
/// Transfer statistics from a node to our own (down) and
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(target_arch = "wasm32", derive(Tsify))]
@ -34,6 +56,14 @@ pub struct TransferStatsDownUp {
pub up: TransferStats,
}
impl fmt::Display for TransferStatsDownUp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "down: {}", self.down)?;
writeln!(f, "up: {}", self.up)?;
Ok(())
}
}
/// Measurement of what states the node has been in over a time span
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(target_arch = "wasm32", derive(Tsify))]
@ -53,6 +83,18 @@ pub struct StateStats {
pub reason: StateReasonStats,
}
impl fmt::Display for StateStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "span: {:?}", self.span)?;
writeln!(f, "reliable: {:?}", self.reliable)?;
writeln!(f, "unreliable: {:?}", self.unreliable)?;
writeln!(f, "dead: {:?}", self.dead)?;
writeln!(f, "punished: {:?}", self.punished)?;
write!(f, "reason:\n{}", indent_all_string(&self.reason))?;
Ok(())
}
}
/// Measurement of what state reasons the node has been in over a time span
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(target_arch = "wasm32", derive(Tsify))]
@ -73,6 +115,32 @@ pub struct StateReasonStats {
pub in_unreliable_ping_span: TimestampDuration,
}
impl fmt::Display for StateReasonStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "(dead) can_not_send: {:?}", self.can_not_send)?;
writeln!(
f,
"(dead) lost_answers: {:?}",
self.too_many_lost_answers
)?;
writeln!(f, "(dead) no_ping_response: {:?}", self.no_ping_response)?;
writeln!(f, "(urel) failed_to_send: {:?}", self.failed_to_send)?;
writeln!(f, "(urel) lost_answers: {:?}", self.lost_answers)?;
writeln!(
f,
"(urel) not_consecutive: {:?}",
self.not_seen_consecutively
)?;
writeln!(
f,
"(urel) unreliable_ping: {:?}",
self.in_unreliable_ping_span
)?;
writeln!(f, "(urel) can_not_send: {:?}", self.can_not_send)?;
Ok(())
}
}
/// Measurement of round-trip RPC question/answer performance
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(target_arch = "wasm32", derive(Tsify))]
@ -99,6 +167,33 @@ pub struct AnswerStats {
pub consecutive_lost_answers_minimum: u32,
}
impl fmt::Display for AnswerStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "span: {:?}", self.span)?;
writeln!(
f,
"questions/answers/lost: {} / {} / {}",
self.questions, self.answers, self.lost_answers
)?;
writeln!(
f,
"consecutive answers min/avg/max: {} / {} / {}",
self.consecutive_answers_minimum,
self.consecutive_answers_average,
self.consecutive_answers_maximum
)?;
writeln!(
f,
"consecutive lost min/avg/max: {} / {} / {}",
self.consecutive_lost_answers_minimum,
self.consecutive_lost_answers_average,
self.consecutive_lost_answers_maximum
)?;
Ok(())
}
}
/// Statistics for RPC operations performed on a node
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(target_arch = "wasm32", derive(Tsify))]
@ -124,6 +219,52 @@ pub struct RPCStats {
pub answer: AnswerStats,
}
impl fmt::Display for RPCStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(
f,
"# sent/received/in-flight: {} / {} / {}",
self.messages_sent, self.messages_rcvd, self.questions_in_flight
)?;
writeln!(
f,
"# recently-lost/failed-to-send: {} / {}",
self.recent_lost_answers, self.failed_to_send
)?;
writeln!(
f,
"last_question: {}",
if let Some(ts) = &self.last_question_ts {
format!("{:?}", ts)
} else {
"None".to_owned()
}
)?;
writeln!(
f,
"last_seen: {}",
if let Some(ts) = &self.last_seen_ts {
format!("{:?}", ts)
} else {
"None".to_owned()
}
)?;
writeln!(
f,
"first_consecutive: {}",
if let Some(ts) = &self.first_consecutive_seen_ts {
format!("{:?}", ts)
} else {
"None".to_owned()
}
)?;
write!(f, "answers:\n{}", indent_all_string(&self.answer))?;
Ok(())
}
}
/// Statistics for a peer in the routing table
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[cfg_attr(target_arch = "wasm32", derive(Tsify))]
@ -143,3 +284,19 @@ pub struct PeerStats {
#[serde(default)]
pub state: StateStats,
}
impl fmt::Display for PeerStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "time_added: {:?}", self.time_added)?;
write!(f, "rpc_stats:\n{}", indent_all_string(&self.rpc_stats))?;
if let Some(ls) = &self.latency {
writeln!(f, "latency: {}", ls)?;
} else {
writeln!(f, "latency: None")?;
}
write!(f, "transfer:\n{}", indent_all_string(&self.transfer))?;
write!(f, "state:\n{}", indent_all_string(&self.state))?;
Ok(())
}
}