sync disk usage

This commit is contained in:
Robin Appelman 2021-03-28 21:56:58 +02:00
commit a81e32d02e
2 changed files with 31 additions and 25 deletions

View file

@ -5,13 +5,11 @@ use crate::sensors::temperatures;
use crate::sensors::*; use crate::sensors::*;
use crate::zfs::pools; use crate::zfs::pools;
use color_eyre::Result; use color_eyre::Result;
use futures_util::pin_mut;
use futures_util::stream::StreamExt;
use std::collections::HashSet; use std::collections::HashSet;
use std::fmt::Write; use std::fmt::Write;
pub async fn get_metrics() -> Result<String> { pub async fn get_metrics() -> Result<String> {
let disk_usage = disk_usage().await?; let disk_usage = disk_usage()?;
let disks = disk_stats()?; let disks = disk_stats()?;
let cpu = cpu_time()?; let cpu = cpu_time()?;
let hostname = hostname()?; let hostname = hostname()?;
@ -19,7 +17,6 @@ pub async fn get_metrics() -> Result<String> {
let temperatures = temperatures()?; let temperatures = temperatures()?;
let pools = pools(); let pools = pools();
let networks = network_stats()?; let networks = network_stats()?;
pin_mut!(disk_usage);
let mut result = String::with_capacity(256); let mut result = String::with_capacity(256);
writeln!(&mut result, "cpu_time{{host=\"{}\"}} {:.1}", hostname, cpu).ok(); writeln!(&mut result, "cpu_time{{host=\"{}\"}} {:.1}", hostname, cpu).ok();
writeln!( writeln!(
@ -90,7 +87,7 @@ pub async fn get_metrics() -> Result<String> {
} }
let mut found_sizes = HashSet::new(); let mut found_sizes = HashSet::new();
while let Some(disk) = disk_usage.next().await { for disk in disk_usage {
let disk: DiskUsage = disk; let disk: DiskUsage = disk;
if disk.size > 0 { if disk.size > 0 {
if found_sizes.insert((disk.size, disk.free)) { if found_sizes.insert((disk.size, disk.free)) {

View file

@ -1,14 +1,12 @@
use color_eyre::{Report, Result}; use color_eyre::{Report, Result};
use futures_util::future;
use futures_util::stream::{Stream, StreamExt};
use heim::disk::{FileSystem, Partition};
use heim::units::information;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use parse_display::Display; use parse_display::Display;
use regex::Regex; use regex::Regex;
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::fs::{read, read_dir, read_to_string, DirEntry, File}; use std::fs::{read, read_dir, read_to_string, DirEntry, File};
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::mem::MaybeUninit;
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
#[derive(Debug, Clone, Hash, Eq, PartialEq, Display)] #[derive(Debug, Clone, Hash, Eq, PartialEq, Display)]
@ -200,22 +198,21 @@ pub fn disk_stats() -> Result<impl Iterator<Item = IOStats>> {
})) }))
} }
pub async fn disk_usage() -> Result<impl Stream<Item = DiskUsage>> { pub fn disk_usage() -> Result<impl Iterator<Item = DiskUsage>> {
Ok(heim::disk::partitions_physical() let stat = BufReader::new(File::open("/proc/mounts")?);
.await? Ok(stat
.filter_map(|result| future::ready(result.ok())) .lines()
.filter(|partition: &Partition| { .filter_map(Result::ok)
future::ready(!partition.file_system().eq(&FileSystem::Zfs)) .filter(|line| line.starts_with('/'))
}) .filter_map(|line: String| {
.filter_map(|partition: Partition| async move { let mount_point = line.split_ascii_whitespace().nth(1)?;
let name = partition.mount_point().to_string_lossy().to_string(); let mount_point = CString::new(mount_point).ok()?;
partition.usage().await.ok().map(|usage| (name, usage)) let stat = statvfs(&mount_point).ok()?;
}) Some(DiskUsage {
.filter(|(mount_point, _usage)| future::ready(!mount_point.contains("/snap/"))) name: mount_point.into_string().unwrap(),
.map(|(mount_point, usage)| DiskUsage { size: stat.f_blocks * stat.f_frsize,
name: mount_point, free: stat.f_bavail * stat.f_frsize,
size: usage.total().get::<information::byte>(), })
free: usage.free().get::<information::byte>(),
})) }))
} }
@ -228,3 +225,15 @@ fn clock_ticks() -> Result<u64> {
Err(Report::msg("Failed to get clock ticks")) Err(Report::msg("Failed to get clock ticks"))
} }
} }
fn statvfs(path: &CStr) -> Result<libc::statvfs> {
let mut vfs = MaybeUninit::<libc::statvfs>::uninit();
let result = unsafe { libc::statvfs(path.as_ptr(), vfs.as_mut_ptr()) };
if result == 0 {
let vfs = unsafe { vfs.assume_init() };
Ok(vfs)
} else {
Err(Report::msg("Failed to stat vfs"))
}
}