zino_http/timing/
timing_metric.rsuse std::{fmt, time::Duration};
use zino_core::SharedString;
#[derive(Debug, Clone)]
pub struct TimingMetric {
name: SharedString,
description: Option<SharedString>,
duration: Duration,
}
impl TimingMetric {
#[inline]
pub fn new(
name: SharedString,
description: Option<SharedString>,
duration: Option<Duration>,
) -> Self {
Self {
name,
description,
duration: duration.unwrap_or_default(),
}
}
#[inline]
pub fn name(&self) -> &str {
self.name.as_ref()
}
#[inline]
pub fn description(&self) -> Option<&str> {
self.description.as_deref()
}
#[inline]
pub fn duration(&self) -> Option<Duration> {
let duration = self.duration;
(duration > Duration::ZERO).then_some(duration)
}
}
impl fmt::Display for TimingMetric {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let name = self.name();
if let Some(duration) = self.duration() {
let mut buffer = ryu::Buffer::new();
let millis = (duration.as_micros() as f64) / 1000.0;
let duration_millis = buffer.format_finite(millis);
if let Some(description) = self.description() {
write!(f, "{name};desc={description};dur={duration_millis}")
} else {
write!(f, "{name};dur={duration_millis}")
}
} else if let Some(description) = self.description() {
write!(f, "{name};desc={description}")
} else {
write!(f, "{name}")
}
}
}
#[cfg(test)]
mod tests {
use super::TimingMetric;
use std::time::Duration;
#[test]
fn it_formats_timing_metric() {
let cache_miss_metric = TimingMetric::new("miss".into(), None, None);
assert_eq!(format!("{cache_miss_metric}"), "miss");
let db_query_metric = TimingMetric::new(
"db".into(),
Some("query".into()),
Some(Duration::from_secs_f64(0.0024635)),
);
assert_eq!(format!("{db_query_metric}"), "db;desc=query;dur=2.463");
let total_timing_metric =
TimingMetric::new("total".into(), None, Some(Duration::from_secs_f64(0.01082)));
assert_eq!(format!("{total_timing_metric}"), "total;dur=10.82");
}
}