feat: implement metrics support

This commit is contained in:
Alex Zenla
2024-04-10 12:58:21 +00:00
parent 183b4ddf73
commit 9b47cd648d
13 changed files with 341 additions and 33 deletions

View File

@ -0,0 +1,90 @@
use anyhow::Result;
use clap::{Parser, ValueEnum};
use comfy_table::{presets::UTF8_FULL_CONDENSED, Table};
use krata::{
events::EventStream,
v1::control::{
control_service_client::ControlServiceClient, ReadGuestMetricsReply,
ReadGuestMetricsRequest,
},
};
use tonic::transport::Channel;
use crate::format::{kv2line, proto2dynamic, proto2kv};
use super::resolve_guest;
#[derive(ValueEnum, Clone, Debug, PartialEq, Eq)]
enum MetricsFormat {
Table,
Json,
JsonPretty,
Yaml,
KeyValue,
}
#[derive(Parser)]
#[command(about = "Read metrics from the guest")]
pub struct MetricsCommand {
#[arg(short, long, default_value = "table", help = "Output format")]
format: MetricsFormat,
#[arg(help = "Guest to read metrics for, either the name or the uuid")]
guest: String,
}
impl MetricsCommand {
pub async fn run(
self,
mut client: ControlServiceClient<Channel>,
_events: EventStream,
) -> Result<()> {
let guest_id: String = resolve_guest(&mut client, &self.guest).await?;
let reply = client
.read_guest_metrics(ReadGuestMetricsRequest { guest_id })
.await?
.into_inner();
match self.format {
MetricsFormat::Table => {
self.print_metrics_table(reply)?;
}
MetricsFormat::Json | MetricsFormat::JsonPretty | MetricsFormat::Yaml => {
let value = serde_json::to_value(proto2dynamic(reply)?)?;
let encoded = if self.format == MetricsFormat::JsonPretty {
serde_json::to_string_pretty(&value)?
} else if self.format == MetricsFormat::Yaml {
serde_yaml::to_string(&value)?
} else {
serde_json::to_string(&value)?
};
println!("{}", encoded.trim());
}
MetricsFormat::KeyValue => {
self.print_key_value(reply)?;
}
}
Ok(())
}
fn print_metrics_table(&self, reply: ReadGuestMetricsReply) -> Result<()> {
let mut table = Table::new();
table.load_preset(UTF8_FULL_CONDENSED);
table.set_content_arrangement(comfy_table::ContentArrangement::Dynamic);
table.set_header(vec!["metric", "value"]);
let kvs = proto2kv(reply)?;
for (key, value) in kvs {
table.add_row(vec![key, value]);
}
println!("{}", table);
Ok(())
}
fn print_key_value(&self, metrics: ReadGuestMetricsReply) -> Result<()> {
let kvs = proto2kv(metrics)?;
println!("{}", kv2line(kvs),);
Ok(())
}
}

View File

@ -3,6 +3,7 @@ pub mod destroy;
pub mod launch;
pub mod list;
pub mod logs;
pub mod metrics;
pub mod resolve;
pub mod watch;
@ -17,7 +18,7 @@ use tonic::{transport::Channel, Request};
use self::{
attach::AttachCommand, destroy::DestroyCommand, launch::LauchCommand, list::ListCommand,
logs::LogsCommand, resolve::ResolveCommand, watch::WatchCommand,
logs::LogsCommand, metrics::MetricsCommand, resolve::ResolveCommand, watch::WatchCommand,
};
#[derive(Parser)]
@ -47,6 +48,7 @@ pub enum Commands {
Logs(LogsCommand),
Watch(WatchCommand),
Resolve(ResolveCommand),
Metrics(MetricsCommand),
}
impl ControlCommand {
@ -82,6 +84,10 @@ impl ControlCommand {
Commands::Resolve(resolve) => {
resolve.run(client).await?;
}
Commands::Metrics(metrics) => {
metrics.run(client, events).await?;
}
}
Ok(())
}