crimes to async

This commit is contained in:
Robin Appelman 2021-03-24 18:17:13 +01:00
commit cd6e103337
5 changed files with 107 additions and 64 deletions

27
Cargo.lock generated
View file

@ -1241,9 +1241,11 @@ dependencies = [
"color-eyre", "color-eyre",
"ctrlc", "ctrlc",
"dotenv", "dotenv",
"futures-lite",
"futures-util", "futures-util",
"heim", "heim",
"libzetta", "libzetta",
"parse-display",
"tokio", "tokio",
"warp", "warp",
] ]
@ -1254,6 +1256,31 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
[[package]]
name = "parse-display"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7271152b3c46c07c729698e7a5248e2744466b3446d222c97a0b1315925a97b1"
dependencies = [
"once_cell",
"parse-display-derive",
"regex",
]
[[package]]
name = "parse-display-derive"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6a9f3e41b237b77c99c09686481c235964ff5878229412b226c451f3e809f4f"
dependencies = [
"once_cell",
"proc-macro2",
"quote",
"regex",
"regex-syntax",
"syn",
]
[[package]] [[package]]
name = "percent-encoding" name = "percent-encoding"
version = "2.1.0" version = "2.1.0"

View file

@ -13,3 +13,5 @@ tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
ctrlc = { version = "3", features = ["termination"] } ctrlc = { version = "3", features = ["termination"] }
dotenv = "0.15" dotenv = "0.15"
futures-util = "0.3" futures-util = "0.3"
futures-lite = "1"
parse-display = "0.4"

View file

@ -1,21 +1,20 @@
use color_eyre::eyre::WrapErr;
use color_eyre::Result; use color_eyre::Result;
use futures_util::future;
use futures_util::stream::{Stream, StreamExt}; use futures_util::stream::{Stream, StreamExt};
use futures_util::{future, TryStreamExt}; use heim::sensors::TemperatureSensor;
use heim::units::{information, ratio, thermodynamic_temperature}; use heim::units::{information, ratio, thermodynamic_temperature};
use parse_display::Display;
use std::collections::HashMap;
use std::time::Duration; use std::time::Duration;
use tokio::time::sleep; use tokio::time::sleep;
#[derive(Debug, Clone)] #[derive(Debug, Clone, Hash, Eq, PartialEq, Display)]
#[display(style = "lowercase")]
pub enum TemperatureLabel { pub enum TemperatureLabel {
CPU, CPU,
} }
#[derive(Debug, Clone)]
pub struct Temperature {
pub sensor: TemperatureLabel,
pub temperature: f32,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Memory { pub struct Memory {
pub total: u64, pub total: u64,
@ -34,26 +33,28 @@ pub struct NetworkStats {
pub struct Heim {} pub struct Heim {}
impl Heim { impl Heim {
#[allow(dead_code)] pub async fn temperatures(&self) -> Result<HashMap<TemperatureLabel, f32>> {
pub async fn temperatures() -> Result<Vec<Temperature>> { // ugly workaround problems between async-fs and tokio
let mut temperatures = Vec::new(); let results = tokio::task::spawn_blocking(|| {
let results: Vec<_> = heim::sensors::temperatures().try_collect().await?; futures_lite::future::block_on(
// let results: Vec<TemperatureSensor> = Vec::new(); heim::sensors::temperatures()
// pin_mut!(results); .collect::<Vec<Result<TemperatureSensor, heim::Error>>>(),
for sensor in results { )
if let Some(temp) = match (sensor.unit(), sensor.label()) { })
("k10temp", Some("Tdie")) => Some(Temperature { .await
sensor: TemperatureLabel::CPU, .wrap_err("Failed to resolve future")?
temperature: sensor .into_iter()
.filter_map(|result| result.ok())
.filter_map(|sensor| match (sensor.unit(), sensor.label()) {
("k10temp", Some("Tdie")) => Some((
TemperatureLabel::CPU,
sensor
.current() .current()
.get::<thermodynamic_temperature::degree_celsius>(), .get::<thermodynamic_temperature::degree_celsius>(),
}), )),
_ => None, _ => None,
} { });
temperatures.push(temp); Ok(results.collect())
}
}
Ok(temperatures)
} }
pub async fn memory(&self) -> Result<Memory> { pub async fn memory(&self) -> Result<Memory> {

View file

@ -1,11 +1,12 @@
mod heim; mod heim;
mod zfs; mod zfs;
use crate::heim::{Heim, Memory, NetworkStats}; use crate::heim::{Heim, Memory, NetworkStats, TemperatureLabel};
use crate::zfs::{ZfsPool, ZFS}; use crate::zfs::{ZfsPool, ZFS};
use color_eyre::{Report, Result}; use color_eyre::{Report, Result};
use futures_util::stream::StreamExt; use futures_util::stream::StreamExt;
use futures_util::{pin_mut, try_join}; use futures_util::{pin_mut, try_join};
use std::collections::HashMap;
use std::fmt::Write; use std::fmt::Write;
use warp::reject::Reject; use warp::reject::Reject;
use warp::{Filter, Rejection}; use warp::{Filter, Rejection};
@ -15,6 +16,7 @@ struct ReportRejection(Report);
impl From<Report> for ReportRejection { impl From<Report> for ReportRejection {
fn from(report: Report) -> Self { fn from(report: Report) -> Self {
eprintln!("{:#}", report);
ReportRejection(report) ReportRejection(report)
} }
} }
@ -22,16 +24,24 @@ impl From<Report> for ReportRejection {
impl Reject for ReportRejection {} impl Reject for ReportRejection {}
async fn get_metrics(heim: Heim, zfs: ZFS) -> Result<String, ReportRejection> { async fn get_metrics(heim: Heim, zfs: ZFS) -> Result<String, ReportRejection> {
let (hostname, pools, cpu, memory, network): (String, Vec<ZfsPool>, f32, Memory, _) = try_join! { let (hostname, pools, cpu, memory, network, temperatures): (
String,
Vec<ZfsPool>,
f32,
Memory,
_,
HashMap<TemperatureLabel, f32>,
) = try_join! {
heim.hostname(), heim.hostname(),
zfs.pools(), zfs.pools(),
heim.cpu_usage(), heim.cpu_usage(),
heim.memory(), heim.memory(),
heim.network_stats(), heim.network_stats(),
heim.temperatures(),
}?; }?;
pin_mut!(network); pin_mut!(network);
let mut result = String::with_capacity(256); let mut result = String::with_capacity(256);
writeln!(&mut result, "cpu_usage{{host=\"{}\"}} {}", hostname, cpu).ok(); writeln!(&mut result, "cpu_usage{{host=\"{}\"}} {:.1}", hostname, cpu).ok();
writeln!( writeln!(
&mut result, &mut result,
"memory_total{{host=\"{}\"}} {}", "memory_total{{host=\"{}\"}} {}",
@ -65,6 +75,7 @@ async fn get_metrics(heim: Heim, zfs: ZFS) -> Result<String, ReportRejection> {
.ok(); .ok();
} }
while let Some(network) = network.next().await { while let Some(network) = network.next().await {
if network.bytes_received > 0 || network.bytes_sent > 0 {
let network: NetworkStats = network; let network: NetworkStats = network;
writeln!( writeln!(
&mut result, &mut result,
@ -79,17 +90,15 @@ async fn get_metrics(heim: Heim, zfs: ZFS) -> Result<String, ReportRejection> {
) )
.ok(); .ok();
} }
// haunted ↓ }
// for temperature in Heim::temperatures().await? { for (label, temp) in temperatures {
// match temperature.sensor { writeln!(
// TemperatureLabel::CPU => writeln!( &mut result,
// &mut result, "temperature{{host=\"{}\", sensor=\"{}\"}} {:.1}",
// "temperature{{host=\"{}\", sensor=\"cpu\"}} {}", hostname, label, temp
// hostname, temperature.temperature )
// ) .ok();
// .ok(), }
// };
// }
Result::<_, ReportRejection>::Ok(result) Result::<_, ReportRejection>::Ok(result)
} }

View file

@ -1,5 +1,6 @@
use color_eyre::Result; use color_eyre::Result;
use libzetta::zpool::{ZpoolEngine, ZpoolOpen3}; use libzetta::zpool::{ZpoolEngine, ZpoolOpen3};
use tokio::task::spawn_blocking;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ZfsPool { pub struct ZfsPool {
@ -21,7 +22,8 @@ impl Default for ZFS {
} }
impl ZFS { impl ZFS {
pub async fn pools(&self) -> Result<Vec<ZfsPool>> { pub async fn pools(self) -> Result<Vec<ZfsPool>> {
spawn_blocking(move || {
let pools = self.engine.all()?; let pools = self.engine.all()?;
pools pools
.into_iter() .into_iter()
@ -34,5 +36,7 @@ impl ZFS {
}) })
}) })
.collect() .collect()
})
.await?
} }
} }