refactoring, log->tracing, gpsd source
This commit is contained in:
151
src/hwmon.rs
151
src/hwmon.rs
@@ -1,23 +1,100 @@
|
||||
use crate::{
|
||||
ChimemonSource, ChimemonSourceChannel, Config, SourceMetric, SourceReport, SourceReportDetails,
|
||||
SourceStatus,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use chimemon::{ChimemonSource, ChimemonSourceChannel, Config};
|
||||
use futures::{stream, StreamExt};
|
||||
use futures::{StreamExt, stream};
|
||||
use influxdb2::models::DataPoint;
|
||||
use log::{debug, info};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::Read,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
use tracing::{Instrument, debug, error, info, info_span, warn};
|
||||
|
||||
pub struct HwmonSource {
|
||||
config: Config,
|
||||
sensors: Vec<HwmonSensor>,
|
||||
sensors: Vec<Arc<HwmonSensor>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct HwmonSensor {
|
||||
path: PathBuf,
|
||||
name: String,
|
||||
value_path: PathBuf,
|
||||
device: String,
|
||||
sensor: String,
|
||||
name: String,
|
||||
label: Option<String>,
|
||||
tags: Arc<Vec<(String, String)>>,
|
||||
}
|
||||
|
||||
impl HwmonSensor {
|
||||
fn new(name: &str, device: &str, sensor: &str) -> Self {
|
||||
let value_path = PathBuf::from(HWMON_ROOT)
|
||||
.join(device)
|
||||
.join(sensor.to_owned() + "_input");
|
||||
let label_path_raw = PathBuf::from(HWMON_ROOT)
|
||||
.join(device)
|
||||
.join(sensor.to_owned() + "_label");
|
||||
let label = if label_path_raw.is_file() {
|
||||
let mut f =
|
||||
File::open(&label_path_raw).expect(&format!("Unable to open `{label_path_raw:?}`"));
|
||||
let mut label = String::new();
|
||||
f.read_to_string(&mut label)
|
||||
.expect(&format!("Unable to read from `{label_path_raw:?}"));
|
||||
Some(label.trim().to_owned())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut tags_vec = vec![
|
||||
("name".to_owned(), name.to_owned()),
|
||||
("device".to_owned(), device.to_owned()),
|
||||
("sensor".to_owned(), sensor.to_owned()),
|
||||
];
|
||||
if let Some(label) = &label {
|
||||
tags_vec.push(("label".to_owned(), label.clone()))
|
||||
}
|
||||
Self {
|
||||
value_path,
|
||||
label,
|
||||
device: device.to_owned(),
|
||||
sensor: sensor.to_owned(),
|
||||
name: name.to_owned(),
|
||||
tags: Arc::new(tags_vec),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct HwmonReport {
|
||||
values: Vec<(Arc<HwmonSensor>, f64)>,
|
||||
}
|
||||
|
||||
impl SourceReportDetails for HwmonReport {
|
||||
fn is_healthy(&self) -> bool {
|
||||
//self.alarms.iter().any(|(_sensor, alarm)| *alarm)
|
||||
true
|
||||
}
|
||||
fn to_metrics(&self) -> Vec<SourceMetric> {
|
||||
let mut metrics = Vec::new();
|
||||
for (sensor, value) in &self.values {
|
||||
metrics.push(SourceMetric::new_float(
|
||||
"hwmon_value",
|
||||
*value,
|
||||
sensor.tags.clone(),
|
||||
))
|
||||
}
|
||||
// for (sensor, alarm) in &self.alarms {
|
||||
// metrics.push(SourceMetric::new_bool(
|
||||
// "hwmon_alarm",
|
||||
// *alarm,
|
||||
// sensor.tags.clone(),
|
||||
// ))
|
||||
// }
|
||||
|
||||
metrics
|
||||
}
|
||||
}
|
||||
|
||||
const HWMON_ROOT: &str = "/sys/class/hwmon";
|
||||
@@ -29,19 +106,14 @@ impl HwmonSource {
|
||||
.hwmon
|
||||
.sensors
|
||||
.iter()
|
||||
.map(|(k, v)| HwmonSensor {
|
||||
name: k.into(),
|
||||
device: v.name.clone(),
|
||||
sensor: v.sensor.clone(),
|
||||
path: PathBuf::from(HWMON_ROOT).join(&v.name).join(&v.sensor),
|
||||
})
|
||||
.map(|(k, v)| Arc::new(HwmonSensor::new(k, &v.name, &v.sensor)))
|
||||
.collect();
|
||||
|
||||
HwmonSource { config, sensors }
|
||||
}
|
||||
|
||||
async fn get_raw_value(sensor: &HwmonSensor) -> Result<String, std::io::Error> {
|
||||
tokio::fs::read_to_string(&sensor.path).await
|
||||
tokio::fs::read_to_string(&sensor.value_path).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,31 +125,38 @@ impl ChimemonSource for HwmonSource {
|
||||
tokio::time::interval(Duration::from_secs(self.config.sources.hwmon.interval));
|
||||
loop {
|
||||
interval.tick().await;
|
||||
let s = stream::iter(&self.sensors).then(|s| async {
|
||||
let sensor_val = HwmonSource::get_raw_value(s)
|
||||
.await
|
||||
.expect("Unable to read sensor");
|
||||
debug!(
|
||||
"hwmon {} raw value {}",
|
||||
s.path.to_string_lossy(),
|
||||
sensor_val
|
||||
);
|
||||
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
|
||||
let mut builder = DataPoint::builder(&self.config.sources.hwmon.measurement)
|
||||
.timestamp(now.as_nanos().try_into().unwrap());
|
||||
for (key, value) in &self.config.influxdb.tags {
|
||||
builder = builder.tag(key, value)
|
||||
let mut values = Vec::new();
|
||||
for s in &self.sensors {
|
||||
if let Ok(sensor_val) = HwmonSource::get_raw_value(s).await {
|
||||
debug!(
|
||||
"hwmon {} raw value {}",
|
||||
s.value_path.to_string_lossy(),
|
||||
sensor_val
|
||||
);
|
||||
if let Ok(parsed) = sensor_val.trim().parse::<f64>() {
|
||||
values.push((s.clone(), parsed));
|
||||
} else {
|
||||
error!(
|
||||
"Unable to parse sensor value {sensor_val} at {}",
|
||||
s.value_path.to_string_lossy()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
error!("Unable to get hwmon sensor value");
|
||||
}
|
||||
builder = builder
|
||||
.tag("name", &s.name)
|
||||
.tag("sensor", &s.sensor)
|
||||
.tag("device", &s.device)
|
||||
.field("value", sensor_val.trim().parse::<i64>().unwrap());
|
||||
builder.build().unwrap()
|
||||
});
|
||||
}
|
||||
let report = SourceReport {
|
||||
name: "hwmon".to_owned(),
|
||||
status: SourceStatus::Healthy,
|
||||
details: Arc::new(HwmonReport { values }),
|
||||
};
|
||||
info!("Writing hwmon data");
|
||||
chan.send(s.collect::<Vec<DataPoint>>().await.into())
|
||||
.unwrap();
|
||||
match chan.send(report.into()) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
warn!("Unable to send to message channel ({e})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user