use std::sync::OnceLock;
use std::time::Instant;
use brz_metrics::Metric;
#[derive(Clone, Copy)]
pub(crate) enum Direction {
Up,
Down,
}
pub(crate) struct ProfileMetrics {
port_name: Box<str>,
up_name: Box<str>,
down_name: Box<str>,
aggregate: OnceLock<Metric>,
up: OnceLock<Metric>,
down: OnceLock<Metric>,
}
impl ProfileMetrics {
pub(crate) fn new(port: u16) -> Self {
Self {
port_name: port.to_string().into_boxed_str(),
up_name: format!("{port}_up").into_boxed_str(),
down_name: format!("{port}_down").into_boxed_str(),
aggregate: OnceLock::new(),
up: OnceLock::new(),
down: OnceLock::new(),
}
}
#[inline]
pub(crate) fn attempt(&self, direction: Direction) -> ProfileAttempt {
let aggregate = *self.aggregate.get_or_init(|| Metric::mc(&self.port_name));
let detail = match direction {
Direction::Up => *self.up.get_or_init(|| Metric::mc_detail(&self.up_name)),
Direction::Down => *self.down.get_or_init(|| Metric::mc_detail(&self.down_name)),
};
ProfileAttempt {
metrics: [aggregate, detail],
started: Instant::now(),
finished: false,
}
}
}
#[derive(Debug)]
pub(crate) struct ProfileAttempt {
metrics: [Metric; 2],
started: Instant,
finished: bool,
}
impl ProfileAttempt {
#[inline]
pub(crate) fn finish(&mut self, success: bool) {
let elapsed = self.started.elapsed();
for metric in self.metrics {
metric.record(elapsed, success);
}
self.finished = true;
}
}
impl Drop for ProfileAttempt {
fn drop(&mut self) {
if !self.finished {
self.finish(false);
}
}
}