implement generic observable

This commit is contained in:
Ondrej Novak 2026-06-14 22:08:05 +02:00
parent 822622d9a9
commit cfa70c946b
Signed by: handy
SSH Key Fingerprint: SHA256:jlNm8ijkaMl4X7+nn3zBFTJufdQgT4unKJoZVH6kYTM
5 changed files with 37 additions and 56 deletions

3
Cargo.lock generated
View File

@ -938,9 +938,6 @@ dependencies = [
[[package]]
name = "protocol"
version = "0.1.0"
dependencies = [
"regex",
]
[[package]]
name = "pxfm"

View File

@ -2,6 +2,3 @@
name = "protocol"
version = "0.1.0"
edition = "2024"
[dependencies]
regex = "1"

View File

@ -1,8 +1,6 @@
use std::io::{Read, Write};
use std::os::unix::net::UnixStream;
use regex::Regex;
use crate::err::ProtocolError;
use crate::message::{
create_list_message, create_request_message, parse_list_response, parse_response_header,
@ -48,15 +46,10 @@ impl Protocol {
}
}
pub fn list(&mut self, path_regex: &Regex) -> Result<Vec<String>, ProtocolError> {
pub fn list(&mut self) -> Result<Vec<String>, ProtocolError> {
let req = create_list_message();
let lines = self.rpc(&req)?;
let values = parse_list_response(lines);
Ok(values
.into_iter()
.filter(|v| path_regex.is_match(v))
.collect())
Ok(parse_list_response(lines))
}
fn rpc(&mut self, req: &str) -> Result<Vec<String>, ProtocolError> {

View File

@ -1,7 +1,7 @@
mod observables;
use draw::{StackedConfig, StackedSeries, StackedSeriesConfig, stacked};
use observables::CpuObservable;
use observables::{Observable, ObservableConfig};
use protocol::Protocol;
use std::{thread, time};
@ -19,7 +19,13 @@ fn main() {
if let Ok(mut proto) = Protocol::new("/var/run/collectd-unixsock") {
// loop {
let cpu = CpuObservable::discover(&mut proto).unwrap();
let cpu_load_cfg = ObservableConfig {
name: "cpu".to_string(),
norm: 1.,
include: vec![Regex::new()],
};
let cpu = Observable::discover(&mut proto).unwrap();
let mut series = StackedSeries::new(cfg);
for _ in 1..10 {
let sample = cpu.sample(&mut proto).unwrap();

View File

@ -1,55 +1,43 @@
use protocol::{Protocol, ProtocolError};
use regex::Regex;
const CPU_NORM: f32 = 100.;
pub struct CpuObservable {
pub struct ObservableConfig {
pub name: String,
num_cpus: u8,
wait_cpus: Vec<String>,
interrupt_cpus: Vec<String>,
load_cpus: Vec<String>,
idle_cpus: Vec<String>,
pub norm: f32,
pub include: Vec<Regex>,
}
impl CpuObservable {
pub fn discover(proto: &mut Protocol) -> Result<CpuObservable, ProtocolError> {
let wait_cpus = proto.list(&Regex::new(".*\\/cpu-[0-9]+\\/cpu-wait").unwrap())?;
let interrupt_cpus =
proto.list(&Regex::new(".*\\/cpu-[0-9]+\\/cpu-(softirq|interrupt)").unwrap())?;
let load_cpus = proto.list(&Regex::new(".*\\/cpu-[0-9]+\\/cpu-.+").unwrap())?;
let idle_cpus = proto.list(&Regex::new(".*\\/cpu-[0-9]+\\/cpu-idle").unwrap())?;
pub struct Observable {
pub name: String,
norm: f32,
metrics: Vec<String>,
}
let num_cpus = wait_cpus.iter().len();
impl Observable {
pub fn discover(
proto: &mut Protocol,
cfg: ObservableConfig,
) -> Result<Observable, ProtocolError> {
let all_values = proto.list()?;
let filtered_values = all_values
.into_iter()
.filter(|v| cfg.include.iter().any(|i| i.is_match(v)))
.collect();
Ok(CpuObservable {
name: "cpu".into(),
num_cpus: num_cpus as u8,
wait_cpus: wait_cpus,
interrupt_cpus: interrupt_cpus,
load_cpus: load_cpus,
idle_cpus: idle_cpus,
Ok(Observable {
name: cfg.name,
norm: cfg.norm,
metrics: filtered_values,
})
}
pub fn sample(&self, proto: &mut Protocol) -> Result<Vec<f32>, ProtocolError> {
let load = self.sample_fields(&self.load_cpus, proto)?;
let iowait = self.sample_fields(&self.wait_cpus, proto)?;
let interrupts = self.sample_fields(&self.interrupt_cpus, proto)?;
let idle = self.sample_fields(&self.idle_cpus, proto)?;
Ok(vec![load - iowait - interrupts - idle, iowait, interrupts])
}
fn sample_fields(
&self,
fields: &Vec<String>,
proto: &mut Protocol,
) -> Result<f32, ProtocolError> {
let results = fields
pub fn sample(&self, proto: &mut Protocol) -> Result<f32, ProtocolError> {
let results = self
.metrics
.iter()
.map(|f| proto.get(f.into(), "value".to_string()))
.collect::<Result<Vec<f32>, ProtocolError>>()?;
Ok(results.into_iter().sum::<f32>() / self.num_cpus as f32 / CPU_NORM)
Ok(results.into_iter().sum::<f32>() / self.norm)
}
}