glean_core/metrics/
rate.rs1use crate::common_metric_data::CommonMetricDataInternal;
6use crate::error_recording::{record_error, test_get_num_recorded_errors, ErrorType};
7use crate::metrics::Metric;
8use crate::metrics::MetricType;
9use crate::storage::StorageManager;
10use crate::CommonMetricData;
11use crate::Glean;
12
13#[derive(Debug, Clone, Eq, PartialEq)]
15pub struct Rate {
16    pub numerator: i32,
18    pub denominator: i32,
20}
21
22impl From<(i32, i32)> for Rate {
23    fn from((num, den): (i32, i32)) -> Self {
24        Self {
25            numerator: num,
26            denominator: den,
27        }
28    }
29}
30
31#[derive(Clone, Debug)]
39pub struct RateMetric {
40    meta: CommonMetricDataInternal,
41}
42
43impl MetricType for RateMetric {
44    fn meta(&self) -> &CommonMetricDataInternal {
45        &self.meta
46    }
47}
48
49impl RateMetric {
54    pub fn new(meta: CommonMetricData) -> Self {
56        Self { meta: meta.into() }
57    }
58
59    pub fn add_to_numerator(&self, amount: i32) {
70        let metric = self.clone();
71        crate::launch_with_glean(move |glean| metric.add_to_numerator_sync(glean, amount))
72    }
73
74    #[doc(hidden)]
75    pub fn add_to_numerator_sync(&self, glean: &Glean, amount: i32) {
76        if !self.should_record(glean) {
77            return;
78        }
79
80        if amount < 0 {
81            record_error(
82                glean,
83                &self.meta,
84                ErrorType::InvalidValue,
85                format!("Added negative value {} to numerator", amount),
86                None,
87            );
88            return;
89        }
90
91        glean
92            .storage()
93            .record_with(glean, &self.meta, |old_value| match old_value {
94                Some(Metric::Rate(num, den)) => Metric::Rate(num.saturating_add(amount), den),
95                _ => Metric::Rate(amount, 0), });
97    }
98
99    pub fn add_to_denominator(&self, amount: i32) {
110        let metric = self.clone();
111        crate::launch_with_glean(move |glean| metric.add_to_denominator_sync(glean, amount))
112    }
113
114    #[doc(hidden)]
115    pub fn add_to_denominator_sync(&self, glean: &Glean, amount: i32) {
116        if !self.should_record(glean) {
117            return;
118        }
119
120        if amount < 0 {
121            record_error(
122                glean,
123                &self.meta,
124                ErrorType::InvalidValue,
125                format!("Added negative value {} to denominator", amount),
126                None,
127            );
128            return;
129        }
130
131        glean
132            .storage()
133            .record_with(glean, &self.meta, |old_value| match old_value {
134                Some(Metric::Rate(num, den)) => Metric::Rate(num, den.saturating_add(amount)),
135                _ => Metric::Rate(0, amount),
136            });
137    }
138
139    pub fn test_get_value(&self, ping_name: Option<String>) -> Option<Rate> {
154        crate::block_on_dispatcher();
155        crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref()))
156    }
157
158    #[doc(hidden)]
160    pub fn get_value<'a, S: Into<Option<&'a str>>>(
161        &self,
162        glean: &Glean,
163        ping_name: S,
164    ) -> Option<Rate> {
165        let queried_ping_name = ping_name
166            .into()
167            .unwrap_or_else(|| &self.meta().inner.send_in_pings[0]);
168
169        match StorageManager.snapshot_metric_for_test(
170            glean.storage(),
171            queried_ping_name,
172            &self.meta.identifier(glean),
173            self.meta.inner.lifetime,
174        ) {
175            Some(Metric::Rate(n, d)) => Some((n, d).into()),
176            _ => None,
177        }
178    }
179
180    pub fn test_get_num_recorded_errors(&self, error: ErrorType) -> i32 {
192        crate::block_on_dispatcher();
193
194        crate::core::with_glean(|glean| {
195            test_get_num_recorded_errors(glean, self.meta(), error).unwrap_or(0)
196        })
197    }
198}