zino_http/timing/
timing_metric.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use std::{fmt, time::Duration};
use zino_core::SharedString;

/// A metric of the performance timing.
#[derive(Debug, Clone)]
pub struct TimingMetric {
    /// Metric name.
    name: SharedString,
    /// Optional description.
    description: Option<SharedString>,
    /// Timing duration. A zero value means that it does not exist.
    duration: Duration,
}

impl TimingMetric {
    /// Creates a new instance.
    #[inline]
    pub fn new(
        name: SharedString,
        description: Option<SharedString>,
        duration: Option<Duration>,
    ) -> Self {
        Self {
            name,
            description,
            duration: duration.unwrap_or_default(),
        }
    }

    /// Returns the name.
    #[inline]
    pub fn name(&self) -> &str {
        self.name.as_ref()
    }

    /// Returns the description.
    #[inline]
    pub fn description(&self) -> Option<&str> {
        self.description.as_deref()
    }

    /// Returns the timing duration.
    #[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");
    }
}