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::CounterMetric;
7 use crate::metrics::Metric;
8 use crate::metrics::MetricType;
9 use crate::metrics::RateMetric;
10 use crate::storage::StorageManager;
11 use crate::CommonMetricData;
12 use crate::Glean;
13 
14 /// A Denominator metric (a kind of count shared among Rate metrics).
15 ///
16 /// Used to count things.
17 /// The value can only be incremented, not decremented.
18 #[derive(Clone, Debug)]
19 pub struct DenominatorMetric {
20     counter: CounterMetric,
21     numerators: Vec<RateMetric>,
22 }
23 
24 impl MetricType for DenominatorMetric {
meta(&self) -> &CommonMetricData25     fn meta(&self) -> &CommonMetricData {
26         self.counter.meta()
27     }
28 
meta_mut(&mut self) -> &mut CommonMetricData29     fn meta_mut(&mut self) -> &mut CommonMetricData {
30         self.counter.meta_mut()
31     }
32 }
33 
34 impl DenominatorMetric {
35     /// Creates a new denominator metric.
new(meta: CommonMetricData, numerators: Vec<CommonMetricData>) -> Self36     pub fn new(meta: CommonMetricData, numerators: Vec<CommonMetricData>) -> Self {
37         Self {
38             counter: CounterMetric::new(meta),
39             numerators: numerators.into_iter().map(RateMetric::new).collect(),
40         }
41     }
42 
43     /// Increases the denominator by `amount`.
44     ///
45     /// # Arguments
46     ///
47     /// * `glean` - The Glean instance this metric belongs to.
48     /// * `amount` - The amount to increase by. Should be positive.
49     ///
50     /// ## Notes
51     ///
52     /// Logs an error if the `amount` is 0 or negative.
add(&self, glean: &Glean, amount: i32)53     pub fn add(&self, glean: &Glean, amount: i32) {
54         if !self.should_record(glean) {
55             return;
56         }
57 
58         if amount <= 0 {
59             record_error(
60                 glean,
61                 self.meta(),
62                 ErrorType::InvalidValue,
63                 format!("Added negative or zero value {}", amount),
64                 None,
65             );
66             return;
67         }
68 
69         for num in &self.numerators {
70             num.add_to_denominator(glean, amount);
71         }
72 
73         glean
74             .storage()
75             .record_with(glean, self.counter.meta(), |old_value| match old_value {
76                 Some(Metric::Counter(old_value)) => {
77                     Metric::Counter(old_value.saturating_add(amount))
78                 }
79                 _ => Metric::Counter(amount),
80             })
81     }
82 
83     /// **Test-only API (exported for FFI purposes).**
84     ///
85     /// Gets the currently stored value as an integer.
86     ///
87     /// This doesn't clear the stored value.
test_get_value(&self, glean: &Glean, storage_name: &str) -> Option<i32>88     pub fn test_get_value(&self, glean: &Glean, storage_name: &str) -> Option<i32> {
89         match StorageManager.snapshot_metric_for_test(
90             glean.storage(),
91             storage_name,
92             &self.meta().identifier(glean),
93             self.meta().lifetime,
94         ) {
95             Some(Metric::Counter(i)) => Some(i),
96             _ => None,
97         }
98     }
99 }
100