metrix/instruments/
mod.rs

1//! Instruments that track values and/or derive values
2//! from observations.
3use std::time::Instant;
4
5use crate::{Observation, ObservedValue, PutsSnapshot, TimeUnit};
6
7pub use self::counter::Counter;
8pub use self::gauge::*;
9pub use self::histogram::Histogram;
10pub use self::instrument_adapter::*;
11pub use self::label_filter::*;
12pub use self::meter::Meter;
13pub use self::other_instruments::*;
14pub use self::panel::*;
15pub use self::polled::*;
16pub use self::switches::*;
17pub use crate::cockpit::Cockpit;
18
19mod counter;
20mod fundamentals;
21mod gauge;
22mod histogram;
23mod instrument_adapter;
24#[cfg(feature = "jemalloc-ctl")]
25pub mod jemalloc;
26mod label_filter;
27mod meter;
28pub mod other_instruments;
29mod panel;
30pub mod polled;
31pub mod switches;
32
33#[derive(Debug, Clone)]
34/// An update instruction for an instrument
35pub enum Update {
36    /// Many observations without a value observed at a given time
37    Observations(u64, Instant),
38    /// One observation without a value observed at a given time
39    Observation(Instant),
40    /// One observation with a value observed at a given time
41    ObservationWithValue(ObservedValue, Instant),
42}
43
44impl Update {
45    pub fn observed_value(&self) -> Option<&ObservedValue> {
46        match self {
47            Update::ObservationWithValue(ref v, _) => Some(v),
48            Update::Observation(_) | Update::Observations(_, _) => None,
49        }
50    }
51}
52
53/// A label with the associated `Update`
54///
55/// This is basically a split `Observation`
56pub struct LabelAndUpdate<T>(pub T, pub Update);
57
58impl<T> From<Observation<T>> for LabelAndUpdate<T> {
59    fn from(obs: Observation<T>) -> LabelAndUpdate<T> {
60        match obs {
61            Observation::Observed {
62                label,
63                count,
64                timestamp,
65                ..
66            } => LabelAndUpdate(label, Update::Observations(count, timestamp)),
67            Observation::ObservedOne {
68                label, timestamp, ..
69            } => LabelAndUpdate(label, Update::Observation(timestamp)),
70            Observation::ObservedOneValue {
71                label,
72                value,
73                timestamp,
74                ..
75            } => LabelAndUpdate(label, Update::ObservationWithValue(value, timestamp)),
76        }
77    }
78}
79
80/// A label with the associated `Update`
81///
82/// This is basically a split `Observation`
83pub struct BorrowedLabelAndUpdate<'a, T: 'a>(pub &'a T, pub Update);
84
85impl<'a, T> From<&'a Observation<T>> for BorrowedLabelAndUpdate<'a, T> {
86    fn from(obs: &'a Observation<T>) -> BorrowedLabelAndUpdate<'a, T> {
87        match obs {
88            Observation::Observed {
89                label,
90                count,
91                timestamp,
92                ..
93            } => BorrowedLabelAndUpdate(label, Update::Observations(*count, *timestamp)),
94            Observation::ObservedOne {
95                label, timestamp, ..
96            } => BorrowedLabelAndUpdate(label, Update::Observation(*timestamp)),
97            Observation::ObservedOneValue {
98                label,
99                value,
100                timestamp,
101                ..
102            } => BorrowedLabelAndUpdate(label, Update::ObservationWithValue(*value, *timestamp)),
103        }
104    }
105}
106
107/// Implementors of `Updates`
108/// can handle `Update`s.
109///
110/// `Update`s are basically observations without a label.
111pub trait Updates {
112    /// Update the internal state according to the given `Update`.
113    ///
114    /// Not all `Update`s might modify the internal state.
115    /// Only those that are appropriate and meaningful for
116    /// the implementor.
117    ///
118    /// Returns the number of instruments updated
119    fn update(&mut self, with: &Update) -> usize;
120}
121
122/// Requirement for an instrument
123pub trait Instrument: Updates + PutsSnapshot {}
124
125fn duration_to_display_value(time: u64, current_unit: TimeUnit, target_unit: TimeUnit) -> u64 {
126    use TimeUnit::*;
127    match (current_unit, target_unit) {
128        (Nanoseconds, Nanoseconds) => time,
129        (Nanoseconds, Microseconds) => time / 1_000,
130        (Nanoseconds, Milliseconds) => time / 1_000_000,
131        (Nanoseconds, Seconds) => time / 1_000_000_000,
132        (Microseconds, Nanoseconds) => time * 1_000,
133        (Microseconds, Microseconds) => time,
134        (Microseconds, Milliseconds) => time / 1_000,
135        (Microseconds, Seconds) => time / 1_000_000,
136        (Milliseconds, Nanoseconds) => time * 1_000_000,
137        (Milliseconds, Microseconds) => time * 1_000,
138        (Milliseconds, Milliseconds) => time,
139        (Milliseconds, Seconds) => time / 1_000,
140        (Seconds, Nanoseconds) => time * 1_000_000_000,
141        (Seconds, Microseconds) => time * 1_000_000,
142        (Seconds, Milliseconds) => time * 1_000,
143        (Seconds, Seconds) => time,
144    }
145}
146
147#[cfg(test)]
148mod test_time_conversion {
149    use super::duration_to_display_value;
150    use crate::TimeUnit;
151
152    #[test]
153    fn duration_to_display_value_from_nanos() {
154        let nanos = 1_234_567_890;
155        assert_eq!(
156            duration_to_display_value(nanos, TimeUnit::Nanoseconds, TimeUnit::Nanoseconds),
157            1_234_567_890,
158            "to nanos"
159        );
160        assert_eq!(
161            duration_to_display_value(nanos, TimeUnit::Nanoseconds, TimeUnit::Microseconds),
162            1_234_567,
163            "to micros"
164        );
165        assert_eq!(
166            duration_to_display_value(nanos, TimeUnit::Nanoseconds, TimeUnit::Milliseconds),
167            1_234,
168            "to millis"
169        );
170        assert_eq!(
171            duration_to_display_value(nanos, TimeUnit::Nanoseconds, TimeUnit::Seconds),
172            1,
173            "to seconds"
174        );
175    }
176
177    #[test]
178    fn duration_to_display_value_from_micros() {
179        let micros = 1_234_567;
180        assert_eq!(
181            duration_to_display_value(micros, TimeUnit::Microseconds, TimeUnit::Nanoseconds),
182            1_234_567_000,
183            "to nanos"
184        );
185        assert_eq!(
186            duration_to_display_value(micros, TimeUnit::Microseconds, TimeUnit::Microseconds),
187            1_234_567,
188            "to micros"
189        );
190        assert_eq!(
191            duration_to_display_value(micros, TimeUnit::Microseconds, TimeUnit::Milliseconds),
192            1_234,
193            "to millis"
194        );
195        assert_eq!(
196            duration_to_display_value(micros, TimeUnit::Microseconds, TimeUnit::Seconds),
197            1,
198            "to seconds"
199        );
200    }
201
202    #[test]
203    fn duration_to_display_value_from_millis() {
204        let millis = 1_234;
205        assert_eq!(
206            duration_to_display_value(millis, TimeUnit::Milliseconds, TimeUnit::Nanoseconds),
207            1_234_000_000,
208            "to nanos"
209        );
210        assert_eq!(
211            duration_to_display_value(millis, TimeUnit::Milliseconds, TimeUnit::Microseconds),
212            1_234_000,
213            "to micros"
214        );
215        assert_eq!(
216            duration_to_display_value(millis, TimeUnit::Milliseconds, TimeUnit::Milliseconds),
217            1_234,
218            "to millis"
219        );
220        assert_eq!(
221            duration_to_display_value(millis, TimeUnit::Milliseconds, TimeUnit::Seconds),
222            1,
223            "to seconds"
224        );
225    }
226
227    #[test]
228    fn duration_to_display_value_from_seconds() {
229        let seconds = 1;
230        assert_eq!(
231            duration_to_display_value(seconds, TimeUnit::Seconds, TimeUnit::Nanoseconds),
232            1_000_000_000,
233            "to nanos"
234        );
235        assert_eq!(
236            duration_to_display_value(seconds, TimeUnit::Seconds, TimeUnit::Microseconds),
237            1_000_000,
238            "to micros"
239        );
240        assert_eq!(
241            duration_to_display_value(seconds, TimeUnit::Seconds, TimeUnit::Milliseconds),
242            1_000,
243            "to millis"
244        );
245        assert_eq!(
246            duration_to_display_value(seconds, TimeUnit::Seconds, TimeUnit::Seconds),
247            1,
248            "to seconds"
249        );
250    }
251}