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::Glean;
10use crate::{CommonMetricData, TestGetValue};
11
12#[derive(Debug, Clone, Eq, PartialEq)]
14pub struct Rate {
15 pub numerator: i32,
17 pub denominator: i32,
19}
20
21impl From<(i32, i32)> for Rate {
22 fn from((num, den): (i32, i32)) -> Self {
23 Self {
24 numerator: num,
25 denominator: den,
26 }
27 }
28}
29
30#[derive(Clone, Debug)]
38pub struct RateMetric {
39 meta: CommonMetricDataInternal,
40}
41
42impl MetricType for RateMetric {
43 fn meta(&self) -> &CommonMetricDataInternal {
44 &self.meta
45 }
46}
47
48impl RateMetric {
53 pub fn new(meta: CommonMetricData) -> Self {
55 Self { meta: meta.into() }
56 }
57
58 pub fn add_to_numerator(&self, amount: i32) {
69 let metric = self.clone();
70 crate::launch_with_glean(move |glean| metric.add_to_numerator_sync(glean, amount))
71 }
72
73 #[doc(hidden)]
74 pub fn add_to_numerator_sync(&self, glean: &Glean, amount: i32) {
75 if !self.should_record(glean) {
76 return;
77 }
78
79 if amount < 0 {
80 record_error(
81 glean,
82 &self.meta,
83 ErrorType::InvalidValue,
84 format!("Added negative value {} to numerator", amount),
85 None,
86 );
87 return;
88 }
89
90 glean
91 .storage()
92 .record_with(glean, &self.meta, |old_value| match old_value {
93 Some(Metric::Rate(num, den)) => Metric::Rate(num.saturating_add(amount), den),
94 _ => Metric::Rate(amount, 0), });
96 }
97
98 pub fn add_to_denominator(&self, amount: i32) {
109 let metric = self.clone();
110 crate::launch_with_glean(move |glean| metric.add_to_denominator_sync(glean, amount))
111 }
112
113 #[doc(hidden)]
114 pub fn add_to_denominator_sync(&self, glean: &Glean, amount: i32) {
115 if !self.should_record(glean) {
116 return;
117 }
118
119 if amount < 0 {
120 record_error(
121 glean,
122 &self.meta,
123 ErrorType::InvalidValue,
124 format!("Added negative value {} to denominator", amount),
125 None,
126 );
127 return;
128 }
129
130 glean
131 .storage()
132 .record_with(glean, &self.meta, |old_value| match old_value {
133 Some(Metric::Rate(num, den)) => Metric::Rate(num, den.saturating_add(amount)),
134 _ => Metric::Rate(0, amount),
135 });
136 }
137
138 #[doc(hidden)]
140 pub fn get_value<'a, S: Into<Option<&'a str>>>(
141 &self,
142 glean: &Glean,
143 ping_name: S,
144 ) -> Option<Rate> {
145 let queried_ping_name = ping_name
146 .into()
147 .unwrap_or_else(|| &self.meta().inner.send_in_pings[0]);
148
149 match glean.storage().get_metric(self.meta(), queried_ping_name) {
150 Some(Metric::Rate(n, d)) => Some((n, d).into()),
151 _ => None,
152 }
153 }
154
155 pub fn test_get_num_recorded_errors(&self, error: ErrorType) -> i32 {
167 crate::block_on_dispatcher();
168
169 crate::core::with_glean(|glean| {
170 test_get_num_recorded_errors(glean, self.meta(), error).unwrap_or(0)
171 })
172 }
173}
174
175impl TestGetValue for RateMetric {
176 type Output = Rate;
177
178 fn test_get_value(&self, ping_name: Option<String>) -> Option<Rate> {
193 crate::block_on_dispatcher();
194 crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref()))
195 }
196}