From c8d2520248519a03e8d04e4e4542492e6e083d2b Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 5 Oct 2021 14:26:59 -0600 Subject: [PATCH] Bugfix/metrics rendering (#586) * stubs for Serialize * serialization instances * render percentages as 100x --- appmgr/src/system.rs | 140 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 10 deletions(-) diff --git a/appmgr/src/system.rs b/appmgr/src/system.rs index 9da24f8de..319a50966 100644 --- a/appmgr/src/system.rs +++ b/appmgr/src/system.rs @@ -1,7 +1,8 @@ use std::fmt; use rpc_toolkit::command; -use serde::{Deserialize, Serialize}; +use serde::ser::SerializeStruct; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; use tokio::sync::broadcast::Receiver; use tokio::sync::RwLock; @@ -28,54 +29,173 @@ pub async fn logs( .await?) } -#[derive(Deserialize, Serialize, Clone, Debug)] +#[derive(Serialize, Deserialize)] +pub struct MetricLeaf { + value: T, + unit: Option, +} + +#[derive(Clone, Debug)] pub struct Celsius(f64); impl fmt::Display for Celsius { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:.1}°C", self.0) } } -#[derive(Deserialize, Serialize, Clone, Debug)] +impl Serialize for Celsius { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + MetricLeaf { + value: format!("{:.1}", self.0), + unit: Some(String::from("°C")), + } + .serialize(serializer) + } +} +impl<'de> Deserialize<'de> for Celsius { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = MetricLeaf::::deserialize(deserializer)?; + Ok(Celsius(s.value.parse().map_err(serde::de::Error::custom)?)) + } +} +#[derive(Clone, Debug)] pub struct Percentage(f64); -#[derive(Deserialize, Serialize, Clone, Debug)] +impl Serialize for Percentage { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + MetricLeaf { + value: format!("{:.1}", self.0), + unit: Some(String::from("%")), + } + .serialize(serializer) + } +} +impl<'de> Deserialize<'de> for Percentage { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = MetricLeaf::::deserialize(deserializer)?; + Ok(Percentage( + s.value.parse().map_err(serde::de::Error::custom)?, + )) + } +} + +#[derive(Clone, Debug)] pub struct MebiBytes(f64); -#[derive(Deserialize, Serialize, Clone, Debug)] +impl Serialize for MebiBytes { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + MetricLeaf { + value: format!("{:.2}", self.0), + unit: Some(String::from("MiB")), + } + .serialize(serializer) + } +} +impl<'de> Deserialize<'de> for MebiBytes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = MetricLeaf::::deserialize(deserializer)?; + Ok(MebiBytes( + s.value.parse().map_err(serde::de::Error::custom)?, + )) + } +} + +#[derive(Clone, Debug)] pub struct GigaBytes(f64); +impl Serialize for GigaBytes { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + MetricLeaf { + value: format!("{:.2}", self.0), + unit: Some(String::from("GB")), + } + .serialize(serializer) + } +} +impl<'de> Deserialize<'de> for GigaBytes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = MetricLeaf::::deserialize(deserializer)?; + Ok(GigaBytes( + s.value.parse().map_err(serde::de::Error::custom)?, + )) + } +} #[derive(Deserialize, Serialize, Clone, Debug)] pub struct MetricsGeneral { + #[serde(rename = "Temparature")] temperature: Celsius, } #[derive(Deserialize, Serialize, Clone, Debug)] pub struct MetricsMemory { + #[serde(rename = "Percentage Used")] percentage_used: Percentage, + #[serde(rename = "Total")] total: MebiBytes, + #[serde(rename = "Available")] available: MebiBytes, + #[serde(rename = "Used")] used: MebiBytes, + #[serde(rename = "Swap Total")] swap_total: MebiBytes, + #[serde(rename = "Swap Free")] swap_free: MebiBytes, + #[serde(rename = "Swap Used")] swap_used: MebiBytes, } #[derive(Deserialize, Serialize, Clone, Debug)] pub struct MetricsCpu { + #[serde(rename = "User Space")] user_space: Percentage, + #[serde(rename = "Kernel Space")] kernel_space: Percentage, + #[serde(rename = "I/O Wait")] wait: Percentage, + #[serde(rename = "Idle")] idle: Percentage, + #[serde(rename = "Usage")] usage: Percentage, } #[derive(Deserialize, Serialize, Clone, Debug)] pub struct MetricsDisk { + #[serde(rename = "Size")] size: GigaBytes, + #[serde(rename = "Used")] used: GigaBytes, + #[serde(rename = "Available")] available: GigaBytes, + #[serde(rename = "Percentage Used")] used_percentage: Percentage, } #[derive(Deserialize, Serialize, Clone, Debug)] pub struct Metrics { + #[serde(rename = "General")] general: MetricsGeneral, + #[serde(rename = "Memory")] memory: MetricsMemory, + #[serde(rename = "CPU")] cpu: MetricsCpu, + #[serde(rename = "Disk")] disk: MetricsDisk, } @@ -358,11 +478,11 @@ async fn get_cpu_info(last: &mut ProcStat) -> Result { let total_new = new.total(); let total_diff = total_new - total_old; let res = MetricsCpu { - user_space: Percentage((new.user() - last.user()) as f64 / total_diff as f64), - kernel_space: Percentage((new.system() - last.system()) as f64 / total_diff as f64), - idle: Percentage((new.idle - last.idle) as f64 / total_diff as f64), - wait: Percentage((new.iowait - last.iowait) as f64 / total_diff as f64), - usage: Percentage((new.used() - last.used()) as f64 / total_diff as f64), + user_space: Percentage((new.user() - last.user()) as f64 * 100.0 / total_diff as f64), + kernel_space: Percentage((new.system() - last.system()) as f64 * 100.0 / total_diff as f64), + idle: Percentage((new.idle - last.idle) as f64 * 100.0 / total_diff as f64), + wait: Percentage((new.iowait - last.iowait) as f64 * 100.0 / total_diff as f64), + usage: Percentage((new.used() - last.used()) as f64 * 100.0 / total_diff as f64), }; *last = new; Ok(res)