Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ toml = "0.8"
# CLI & Logging
clap = { version = "4.0", features = ["derive"] }
tracing = "0.1"
tracing-subscriber = "0.3"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing-appender = "0.2"
comfy-table = "7.1"
indicatif = "0.17"

Expand Down
267 changes: 94 additions & 173 deletions src/actors/monitor/txn_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::time::{Duration, Instant};

use alloy::consensus::Account;
use alloy::primitives::TxHash;
use comfy_table::{presets::UTF8_FULL, Attribute, Cell, Color, Table};
use comfy_table::{presets::UTF8_FULL, Cell, Table};
use tracing::{debug, error, warn};

use crate::actors::monitor::SubmissionResult;
Expand Down Expand Up @@ -615,22 +615,6 @@ impl TxnTracker {
)
};

let mut plan_summaries = Vec::new();

if !self.plan_trackers.is_empty() {
for (_plan_id, tracker) in &self.plan_trackers {
plan_summaries.push(format!(
"{}: {}/{}",
tracker.plan_name, tracker.resolved_transactions, tracker.produce_transactions
));
}
} else if let Some((_plan_id, tracker)) = &self.last_completed_plan {
plan_summaries.push(format!(
"{}: {}/{} done",
tracker.plan_name, tracker.resolved_transactions, tracker.produce_transactions
));
}

// Calculate success rate
let success_rate = if self.total_produced_transactions > 0 {
self.total_resolved_transactions as f64 / self.total_produced_transactions as f64
Expand All @@ -639,177 +623,114 @@ impl TxnTracker {
0.0
};

let mut table = Table::new();
table.load_preset(UTF8_FULL);

// Set table header
table.set_header(vec![
"Plan Name",
"Progress",
"Success%",
"SendFail",
"ExecFail",
"Status",
]);

// Add individual plan rows
if !self.plan_trackers.is_empty() {
for (_plan_id, tracker) in &self.plan_trackers {
let plan_success_rate = if tracker.resolved_transactions > 0 {
let successful = tracker
.resolved_transactions
.saturating_sub(tracker.failed_submissions + tracker.failed_executions);
successful as f64 / tracker.resolved_transactions as f64 * 100.0
} else if tracker.produce_transactions > 0 {
// If no transactions resolved yet, can't calculate success rate
0.0
} else {
100.0
};

let progress_color =
if tracker.resolved_transactions as usize >= tracker.produce_transactions {
Color::Green
} else {
Color::Yellow
};
// Count plan states
let mut produced_plans = 0u64;
let mut not_produced_plans = 0u64;
let mut completed_plans = 0u64;
let mut in_progress_plans = 0u64;
let mut timed_out_txns = 0u64;

let status = if tracker.plan_produced
&& tracker.resolved_transactions as usize >= tracker.produce_transactions
{
if tracker.failed_submissions + tracker.failed_executions > 0 {
"Completed (w/ Errors)"
} else {
"Completed"
}
for (_plan_id, tracker) in &self.plan_trackers {
if tracker.plan_produced {
produced_plans += 1;
if tracker.resolved_transactions as usize >= tracker.produce_transactions {
completed_plans += 1;
} else {
"In Progress"
};
in_progress_plans += 1;
}
} else {
not_produced_plans += 1;
}
}

table.add_row(vec![
Cell::new(&tracker.plan_name).fg(Color::Cyan),
Cell::new(&format!(
"{}/{}",
format_large_number(tracker.resolved_transactions),
format_large_number(tracker.produce_transactions as u64)
))
.fg(progress_color),
Cell::new(&format!("{:.1}", plan_success_rate)).fg(
if plan_success_rate >= 95.0 {
Color::Green
} else if plan_success_rate >= 80.0 {
Color::Yellow
} else {
Color::Red
},
),
Cell::new(&format_large_number(tracker.failed_submissions)).fg(
if tracker.failed_submissions > 0 {
Color::Red
} else {
Color::Green
},
),
Cell::new(&format_large_number(tracker.failed_executions)).fg(
if tracker.failed_executions > 0 {
Color::Red
} else {
Color::Green
},
),
Cell::new(status).fg(if status.contains("Completed") {
Color::Green
} else {
Color::Yellow
}),
]);
// Count timed out pending txns (those waiting > RETRY_TIMEOUT)
for pending_info in &self.pending_txns {
if pending_info.submit_time.elapsed() > RETRY_TIMEOUT {
timed_out_txns += 1;
}
} else if let Some((_plan_id, tracker)) = &self.last_completed_plan {
let plan_success_rate = if tracker.resolved_transactions > 0 {
let successful = tracker
.resolved_transactions
.saturating_sub(tracker.failed_submissions + tracker.failed_executions);
successful as f64 / tracker.resolved_transactions as f64 * 100.0
} else {
100.0
};

table.add_row(vec![
Cell::new(&format!("{} (Last)", tracker.plan_name)).fg(Color::DarkGrey),
Cell::new(&format!(
"{}/{}",
format_large_number(tracker.resolved_transactions),
format_large_number(tracker.produce_transactions as u64)
))
.fg(Color::Green),
Cell::new(&format!("{:.1}", plan_success_rate)).fg(Color::Green),
Cell::new(&format_large_number(tracker.failed_submissions)).fg(
if tracker.failed_submissions > 0 {
Color::Red
} else {
Color::Green
},
),
Cell::new(&format_large_number(tracker.failed_executions)).fg(
if tracker.failed_executions > 0 {
Color::Red
} else {
Color::Green
},
),
Cell::new("Done").fg(Color::Green),
]);
}

// Add summary row
let pending_txns = self.pending_txns.len() as u64;

let mut table = Table::new();
table.load_preset(UTF8_FULL);

// Set table header - summary statistics
table.set_header(vec![
"Metric",
"Value",
"Metric",
"Value",
]);

// Row 1: Txn progress and TPS
table.add_row(vec![
Cell::new("TOTAL")
.add_attribute(Attribute::Bold)
.fg(Color::Blue),
Cell::new("Progress"),
Cell::new(&format!(
"{}/{}",
format_large_number(self.total_resolved_transactions),
format_large_number(self.total_produced_transactions)
))
.add_attribute(Attribute::Bold)
.fg(Color::Blue),
Cell::new(&format!("{:.1}", success_rate))
.add_attribute(Attribute::Bold)
.fg(Color::Blue),
Cell::new(&format_large_number(self.total_failed_submissions))
.add_attribute(Attribute::Bold)
.fg(Color::Blue),
Cell::new(&format_large_number(self.total_failed_executions))
.add_attribute(Attribute::Bold)
.fg(Color::Blue),
Cell::new(&format!(
"TPS:{:.1} | Lat: {:.1}s | Pool:{}/{}",
tps,
avg_latency.as_secs_f64(),
format_large_number(self.mempool_pending),
format_large_number(self.mempool_queued)
))
.add_attribute(Attribute::Bold)
.fg(Color::Magenta),
)),
Cell::new("TPS"),
Cell::new(&format!("{:.1}", tps)),
]);

// Row 2: Pending txns and latency
table.add_row(vec![
Cell::new("SYSTEM")
.add_attribute(Attribute::Bold)
.fg(Color::Yellow),
Cell::new(""), // Progress placeholder
Cell::new(""), // Success% placeholder
Cell::new(""), // SendFail placeholder
Cell::new(""), // ExecFail placeholder
Cell::new(&format!(
"Ready Accounts: {} | Processing: {}",
format_large_number(self.producer_ready_accounts),
format_large_number(self.producer_sending_txns)
))
.add_attribute(Attribute::Bold)
.fg(Color::Yellow),
Cell::new("Pending Txns"),
Cell::new(&format_large_number(pending_txns)),
Cell::new("Avg Latency"),
Cell::new(&format!("{:.1}s", avg_latency.as_secs_f64())),
]);

// Row 3: Timed out txns and success rate
table.add_row(vec![
Cell::new("Timed Out Txns"),
Cell::new(&format_large_number(timed_out_txns)),
Cell::new("Success%"),
Cell::new(&format!("{:.1}%", success_rate)),
]);

// Row 4: Produced plans and not produced plans
table.add_row(vec![
Cell::new("Produced Plans"),
Cell::new(&format_large_number(produced_plans)),
Cell::new("Not Produced"),
Cell::new(&format_large_number(not_produced_plans)),
]);

// Row 5: Completed plans and in progress plans
table.add_row(vec![
Cell::new("Completed Plans"),
Cell::new(&format_large_number(completed_plans)),
Cell::new("In Progress"),
Cell::new(&format_large_number(in_progress_plans)),
]);

// Row 6: Send failures and execution failures
table.add_row(vec![
Cell::new("Send Failures"),
Cell::new(&format_large_number(self.total_failed_submissions)),
Cell::new("Exec Failures"),
Cell::new(&format_large_number(self.total_failed_executions)),
]);

// Row 7: Mempool stats
table.add_row(vec![
Cell::new("Pool Pending"),
Cell::new(&format_large_number(self.mempool_pending)),
Cell::new("Pool Queued"),
Cell::new(&format_large_number(self.mempool_queued)),
]);

// Row 8: Producer stats
table.add_row(vec![
Cell::new("Ready Accounts"),
Cell::new(&format_large_number(self.producer_ready_accounts)),
Cell::new("Processing"),
Cell::new(&format_large_number(self.producer_sending_txns)),
]);

println!("{}", table);
tracing::info!("\n{}", table);
}
}
6 changes: 6 additions & 0 deletions src/config/bench_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ pub struct BenchConfig {
pub enable_swap_token: bool,
#[serde(default)]
pub address_pool_type: AddressPoolType,
#[serde(default = "default_log_path")]
pub log_path: String,
}

fn default_log_path() -> String {
"./log.log".to_string()
}

/// Node and chain configuration
Expand Down
Loading
Loading