metrix/instruments/
counter.rs

1use crate::instruments::{
2    AcceptAllLabels, Instrument, InstrumentAdapter, LabelFilter, LabelPredicate, Update, Updates,
3};
4use crate::snapshot::Snapshot;
5use crate::util;
6use crate::{Descriptive, PutsSnapshot};
7
8/// A simple ever increasing counter
9///
10/// Reacts to the following `Observation`s:
11///
12/// * `Observation::Observed`(Update::Observations)
13/// * `Obervation::ObservedOne`(Update::Observation)
14/// * `Obervation::ObservedOneValue`(Update::ObservationWithValue)
15///
16/// # Example
17///
18/// ```
19/// use std::time::Instant;
20/// use metrix::instruments::*;
21///
22/// let mut counter = Counter::new_with_defaults("example");
23/// let update = Update::Observation(Instant::now());
24/// counter.update(&update);
25///
26/// assert_eq!(1, counter.get());
27/// ```
28pub struct Counter {
29    name: String,
30    title: Option<String>,
31    description: Option<String>,
32    count: u64,
33}
34
35impl Counter {
36    pub fn new<T: Into<String>>(name: T) -> Counter {
37        Counter {
38            name: name.into(),
39            title: None,
40            description: None,
41            count: 0,
42        }
43    }
44    pub fn new_with_defaults<T: Into<String>>(name: T) -> Counter {
45        Self::new(name)
46    }
47
48    pub fn get_name(&self) -> &str {
49        &self.name
50    }
51
52    pub fn set_name<T: Into<String>>(&mut self, name: T) {
53        self.name = name.into();
54    }
55
56    pub fn name<T: Into<String>>(mut self, name: T) -> Self {
57        self.set_name(name);
58        self
59    }
60
61    pub fn set_title<T: Into<String>>(&mut self, title: T) {
62        self.title = Some(title.into())
63    }
64
65    pub fn title<T: Into<String>>(mut self, title: T) -> Self {
66        self.set_title(title);
67        self
68    }
69
70    pub fn set_description<T: Into<String>>(&mut self, description: T) {
71        self.description = Some(description.into())
72    }
73
74    pub fn description<T: Into<String>>(mut self, description: T) -> Self {
75        self.set_description(description);
76        self
77    }
78
79    /// Increase the stored value by one.
80    pub fn inc(&mut self) {
81        self.count += 1;
82    }
83
84    /// Increase the stored value by `n`
85    pub fn inc_by(&mut self, n: u64) {
86        self.count += n;
87    }
88
89    /// Get the current value
90    pub fn get(&self) -> u64 {
91        self.count
92    }
93
94    pub fn accept<L: Eq + Send + 'static, F: Into<LabelFilter<L>>>(
95        self,
96        accept: F,
97    ) -> InstrumentAdapter<L, Self> {
98        InstrumentAdapter::accept(accept, self)
99    }
100
101    /// Creates an `InstrumentAdapter` that makes this instrument
102    /// react on observations on the given label.
103    pub fn for_label<L: Eq + Send + 'static>(self, label: L) -> InstrumentAdapter<L, Self> {
104        self.accept(label)
105    }
106
107    /// Creates an `InstrumentAdapter` that makes this instrument
108    /// react on observations with the given labels.
109    ///
110    /// If `labels` is empty the instrument will not react to any observations
111    pub fn for_labels<L: Eq + Send + 'static>(self, labels: Vec<L>) -> InstrumentAdapter<L, Self> {
112        self.accept(labels)
113    }
114
115    /// Creates an `InstrumentAdapter` that makes this instrument react on
116    /// all observations.
117    pub fn for_all_labels<L: Eq + Send + 'static>(self) -> InstrumentAdapter<L, Self> {
118        self.accept(AcceptAllLabels)
119    }
120
121    /// Creates an `InstrumentAdapter` that makes this instrument react on
122    /// observations with labels specified by the predicate.
123    pub fn for_labels_by_predicate<L, P>(self, label_predicate: P) -> InstrumentAdapter<L, Self>
124    where
125        L: Eq + Send + 'static,
126        P: Fn(&L) -> bool + Send + 'static,
127    {
128        self.accept(LabelPredicate(label_predicate))
129    }
130
131    /// Creates an `InstrumentAdapter` that makes this instrument to no
132    /// observations.
133    pub fn adapter<L: Eq + Send + 'static>(self) -> InstrumentAdapter<L, Self> {
134        InstrumentAdapter::deaf(self)
135    }
136}
137
138impl Instrument for Counter {}
139
140impl PutsSnapshot for Counter {
141    fn put_snapshot(&self, into: &mut Snapshot, descriptive: bool) {
142        util::put_postfixed_descriptives(self, &self.name, into, descriptive);
143        into.items.push((self.name.clone(), self.count.into()));
144    }
145}
146
147impl Updates for Counter {
148    fn update(&mut self, with: &Update) -> usize {
149        match *with {
150            Update::Observation(_) => {
151                self.inc();
152                1
153            }
154            Update::Observations(n, _) => {
155                self.inc_by(n);
156                1
157            }
158            Update::ObservationWithValue(_, _) => {
159                self.inc();
160                1
161            }
162        }
163    }
164}
165
166impl Descriptive for Counter {
167    fn title(&self) -> Option<&str> {
168        self.title.as_deref()
169    }
170
171    fn description(&self) -> Option<&str> {
172        self.description.as_deref()
173    }
174}
175
176#[cfg(test)]
177mod test {
178    use std::time::Instant;
179
180    use super::*;
181
182    #[test]
183    fn updates() {
184        let mut counter = Counter::new("");
185
186        assert_eq!(counter.get(), 0);
187
188        counter.update(&Update::Observation(Instant::now()));
189        assert_eq!(counter.get(), 1);
190
191        counter.update(&Update::Observations(1, Instant::now()));
192        assert_eq!(counter.get(), 2);
193
194        counter.update(&Update::Observations(3, Instant::now()));
195        assert_eq!(counter.get(), 5);
196
197        counter.update(&Update::ObservationWithValue(33.into(), Instant::now()));
198        assert_eq!(counter.get(), 6);
199    }
200}