1 // This Source Code Form is subject to the terms of the Mozilla Public
2 // License, v. 2.0. If a copy of the MPL was not distributed with this
3 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 
5 use crate::error_recording::{record_error, ErrorType};
6 use crate::metrics::Metric;
7 use crate::metrics::MetricType;
8 use crate::storage::StorageManager;
9 use crate::CommonMetricData;
10 use crate::Glean;
11 
12 /// A counter metric.
13 ///
14 /// Used to count things.
15 /// The value can only be incremented, not decremented.
16 #[derive(Clone, Debug)]
17 pub struct CounterMetric {
18     meta: CommonMetricData,
19 }
20 
21 impl MetricType for CounterMetric {
meta(&self) -> &CommonMetricData22     fn meta(&self) -> &CommonMetricData {
23         &self.meta
24     }
25 
meta_mut(&mut self) -> &mut CommonMetricData26     fn meta_mut(&mut self) -> &mut CommonMetricData {
27         &mut self.meta
28     }
29 }
30 
31 // IMPORTANT:
32 //
33 // When changing this implementation, make sure all the operations are
34 // also declared in the related trait in `../traits/`.
35 impl CounterMetric {
36     /// Creates a new counter metric.
new(meta: CommonMetricData) -> Self37     pub fn new(meta: CommonMetricData) -> Self {
38         Self { meta }
39     }
40 
41     /// Increases the counter by `amount`.
42     ///
43     /// # Arguments
44     ///
45     /// * `glean` - The Glean instance this metric belongs to.
46     /// * `amount` - The amount to increase by. Should be positive.
47     ///
48     /// ## Notes
49     ///
50     /// Logs an error if the `amount` is 0 or negative.
add(&self, glean: &Glean, amount: i32)51     pub fn add(&self, glean: &Glean, amount: i32) {
52         if !self.should_record(glean) {
53             return;
54         }
55 
56         if amount <= 0 {
57             record_error(
58                 glean,
59                 &self.meta,
60                 ErrorType::InvalidValue,
61                 format!("Added negative or zero value {}", amount),
62                 None,
63             );
64             return;
65         }
66 
67         glean
68             .storage()
69             .record_with(glean, &self.meta, |old_value| match old_value {
70                 Some(Metric::Counter(old_value)) => {
71                     Metric::Counter(old_value.saturating_add(amount))
72                 }
73                 _ => Metric::Counter(amount),
74             })
75     }
76 
77     /// **Test-only API (exported for FFI purposes).**
78     ///
79     /// Gets the currently stored value as an integer.
80     ///
81     /// This doesn't clear the stored value.
test_get_value(&self, glean: &Glean, storage_name: &str) -> Option<i32>82     pub fn test_get_value(&self, glean: &Glean, storage_name: &str) -> Option<i32> {
83         match StorageManager.snapshot_metric_for_test(
84             glean.storage(),
85             storage_name,
86             &self.meta.identifier(glean),
87             self.meta.lifetime,
88         ) {
89             Some(Metric::Counter(i)) => Some(i),
90             _ => None,
91         }
92     }
93 }
94