From d01bf894f205eca93118ea7ad67002f7db6a6f51 Mon Sep 17 00:00:00 2001 From: Joshua Jerin Date: Tue, 5 Mar 2024 15:25:27 -0500 Subject: [PATCH] Prettify top (#614) --- tembo-cli/Cargo.lock | 115 +++++++++++++++++++++++++++++++++++++++ tembo-cli/Cargo.toml | 1 + tembo-cli/src/cmd/top.rs | 66 +++++++++++++--------- 3 files changed, 156 insertions(+), 26 deletions(-) diff --git a/tembo-cli/Cargo.lock b/tembo-cli/Cargo.lock index d4947cacc..d6dafacb7 100644 --- a/tembo-cli/Cargo.lock +++ b/tembo-cli/Cargo.lock @@ -1197,6 +1197,12 @@ dependencies = [ "serde", ] +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.33" @@ -1856,6 +1862,17 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -2904,6 +2921,20 @@ dependencies = [ "termtree", ] +[[package]] +name = "prettytable-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" +dependencies = [ + "csv", + "encode_unicode", + "is-terminal", + "lazy_static", + "term", + "unicode-width", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -3331,6 +3362,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.15" @@ -4012,6 +4049,7 @@ dependencies = [ "mockall", "openssl", "predicates 2.1.5", + "prettytable-rs", "random-string", "reqwest", "rpassword", @@ -4112,6 +4150,17 @@ dependencies = [ "unic-segment", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -4986,6 +5035,15 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.4", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -5016,6 +5074,21 @@ dependencies = [ "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -5028,6 +5101,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -5040,6 +5119,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -5052,6 +5137,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -5064,6 +5155,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -5076,6 +5173,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -5088,6 +5191,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -5100,6 +5209,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + [[package]] name = "winnow" version = "0.5.15" diff --git a/tembo-cli/Cargo.toml b/tembo-cli/Cargo.toml index f3150d77f..ce0c31bc7 100644 --- a/tembo-cli/Cargo.toml +++ b/tembo-cli/Cargo.toml @@ -30,6 +30,7 @@ futures = "0.3.30" actix-cors = "0.7.0" clap_complete = "4.3.2" serde = { version = "1.0", features = ["derive"] } +prettytable-rs = "0.10.0" serde_json = "1.0.91" crossterm = "0.27.0" serde_yaml = "0.9.17" diff --git a/tembo-cli/src/cmd/top.rs b/tembo-cli/src/cmd/top.rs index 7fd088177..fd4d4791a 100644 --- a/tembo-cli/src/cmd/top.rs +++ b/tembo-cli/src/cmd/top.rs @@ -8,6 +8,7 @@ use crossterm::{ execute, terminal::{Clear, ClearType}, }; +use prettytable::{row, Table}; use reqwest::header::HeaderMap; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -77,10 +78,13 @@ async fn fetch_metrics_loop( env: Environment, instance_settings: HashMap, profile: &Profile, + tail: bool, ) -> Result<()> { let mut stdout = stdout(); let client = reqwest::Client::new(); let url = profile.get_tembo_data_host(); + let mut table = Table::new(); + table.add_row(row!["Instance", "CPU", "Storage", "Memory"]); let mut headers = HeaderMap::new(); headers.insert("Accept", "application/json".parse()?); @@ -90,14 +94,18 @@ async fn fetch_metrics_loop( .expect("JWT Token is not configured"); headers.insert("Authorization", format!("Bearer {}", jwt_token).parse()?); - execute!(stdout, Clear(ClearType::All))?; + if tail { + execute!(stdout, Clear(ClearType::All))?; + } for value in instance_settings.values() { let org_name = get_instance_org_name(config, &env, &value.instance_name).await?; let namespace = format!("org-{}-inst-{}", org_name, &value.instance_name); let namespace_encoded = urlencoding::encode(&namespace); - println!("Instance: {}", &value.instance_name); + let mut cpu_value = String::new(); + let mut memory_value = String::new(); + let mut storage_value = String::new(); let metric_queries = vec![ ( @@ -126,13 +134,6 @@ async fn fetch_metrics_loop( namespace_encoded ) ), - /*Doubtful if we would need Connections(Need to consult Steven) - ( - "Connections", - format!("max by (pod) (cnpg_backends_max_tx_duration_seconds{{namespace=\"{}\"}})", namespace_encoded), - format!("" - ) - ),*/ ]; for (query_name, query1, query2) in &metric_queries { @@ -173,15 +174,13 @@ async fn fetch_metrics_loop( 0.0 } }; - - let value1 = format!("{:.2}", raw_value1.abs()); - - if *query_name == "Storage" || *query_name == "Memory" { - let value2 = format!("{:.2}", raw_value2.abs()); - println!("{}: {} | {}%", query_name, value2, value1); - } else { - let value2 = format!("{}", raw_value2.abs()); - println!("{}: {} | {}%", query_name, value2, value1); + match *query_name { + "Cpu" => cpu_value = format!("{:.2}/{:.2}%", raw_value2, raw_value1), + "Memory" => memory_value = format!("{:.2}/{:.2}%", raw_value2, raw_value1), + "Storage" => { + storage_value = format!("{:.2}/{:.2}%", raw_value2, raw_value1) + } + _ => (), } } (Err(e), _) | (_, Err(e)) => { @@ -189,10 +188,14 @@ async fn fetch_metrics_loop( } } } - - println!(); + table.add_row(row![ + value.instance_name, + cpu_value, + storage_value, + memory_value + ]); } - + table.printstd(); stdout.flush()?; Ok(()) } @@ -271,9 +274,14 @@ pub fn execute(verbose: bool, top_command: TopCommand) -> Result<(), anyhow::Err let rt = Runtime::new().map_err(|e| anyhow!("Failed to create Tokio runtime: {}", e))?; rt.block_on(async { loop { - if let Err(e) = - fetch_metrics_loop(&config, env.clone(), instance_settings.clone(), profile) - .await + if let Err(e) = fetch_metrics_loop( + &config, + env.clone(), + instance_settings.clone(), + profile, + true, + ) + .await { eprintln!("Error fetching metrics: {}", e); } @@ -283,8 +291,14 @@ pub fn execute(verbose: bool, top_command: TopCommand) -> Result<(), anyhow::Err } else { let rt = Runtime::new().map_err(|e| anyhow!("Failed to create Tokio runtime: {}", e))?; rt.block_on(async { - if let Err(e) = - fetch_metrics_loop(&config, env.clone(), instance_settings.clone(), profile).await + if let Err(e) = fetch_metrics_loop( + &config, + env.clone(), + instance_settings.clone(), + profile, + false, + ) + .await { eprintln!("Error fetching metrics: {}", e); }