use std::{fs::read_to_string, str::FromStr};
use crate::metrics::{
system_metrics::SystemMetricFamilyCollector, KeyedMetricReading, MetricStringKey,
};
use eyre::{eyre, Result};
const SYS_CLASS_THERMAL_PATH: &str = "/sys/class/thermal";
pub const THERMAL_METRIC_NAMESPACE: &str = "thermal";
pub struct ThermalMetricsCollector;
impl ThermalMetricsCollector {
pub fn new() -> Self {
ThermalMetricsCollector {}
}
fn read_thermal_zone_temp(zone_name: &str, root_dir: &str) -> Result<KeyedMetricReading> {
let temp_file = format!("{}/{}/temp", root_dir, zone_name);
let type_file = format!("{}/{}/type", root_dir, zone_name);
let temp_in_celsius = read_to_string(temp_file)?.trim().parse::<f64>()? / 1000.0;
let thermal_zone_type = read_to_string(type_file)?.trim().to_string();
Ok(KeyedMetricReading::new_histogram(
MetricStringKey::from_str(
format!("{}/{}/temp", THERMAL_METRIC_NAMESPACE, thermal_zone_type).as_str(),
)
.map_err(|e| {
eyre!(
"Failed to construct MetricStringKey for thermal zone: {}",
e
)
})?,
temp_in_celsius,
))
}
fn read_thermal_metrics_from_dir(dir: &str) -> Result<Vec<KeyedMetricReading>> {
let metrics: Vec<_> = std::fs::read_dir(dir)?
.filter_map(|entry| entry.ok())
.map(|entry| entry.path())
.filter_map(|path| Some(path.file_name()?.to_str()?.to_string()))
.filter(|name| name.starts_with("thermal_zone"))
.filter_map(|name| Self::read_thermal_zone_temp(&name, dir).ok())
.collect();
Ok(metrics)
}
pub fn get_thermal_metrics() -> Result<Vec<KeyedMetricReading>> {
Self::read_thermal_metrics_from_dir(SYS_CLASS_THERMAL_PATH)
}
}
impl SystemMetricFamilyCollector for ThermalMetricsCollector {
fn family_name(&self) -> &'static str {
THERMAL_METRIC_NAMESPACE
}
fn collect_metrics(&mut self) -> Result<Vec<KeyedMetricReading>> {
Self::get_thermal_metrics()
}
}
#[cfg(test)]
mod tests {
use super::*;
use insta::{assert_json_snapshot, rounded_redaction};
use std::fs::File;
use std::io::Write;
use tempfile::tempdir;
#[test]
fn test_read_thermal_zone_temp() {
let dir = tempdir().unwrap();
let thermal_zone_dir = dir.path().join("thermal_zone0");
std::fs::create_dir(&thermal_zone_dir).unwrap();
let temp_file_path = thermal_zone_dir.join("temp");
let mut temp_file = File::create(temp_file_path).unwrap();
writeln!(temp_file, "50000").unwrap();
let type_file_path = thermal_zone_dir.join("type");
let mut type_file = File::create(type_file_path).unwrap();
writeln!(type_file, "cpu-temp").unwrap();
let result = ThermalMetricsCollector::read_thermal_zone_temp(
"thermal_zone0",
dir.path().to_str().unwrap(),
)
.unwrap();
assert_json_snapshot!(result, {".value.**.timestamp" => "[timestamp]", ".value.**.value" => rounded_redaction(5)});
dir.close().unwrap();
}
}