glean_core/metrics/
counter.rs1use std::cmp::Ordering;
6use std::sync::Arc;
7
8use crate::common_metric_data::{CommonMetricDataInternal, MetricLabel};
9use crate::error_recording::{record_error, test_get_num_recorded_errors, ErrorType};
10use crate::metrics::Metric;
11use crate::metrics::MetricType;
12use crate::Glean;
13use crate::{CommonMetricData, TestGetValue};
14
15#[derive(Clone, Debug)]
20pub struct CounterMetric {
21 meta: Arc<CommonMetricDataInternal>,
22}
23
24impl MetricType for CounterMetric {
25 fn meta(&self) -> &CommonMetricDataInternal {
26 &self.meta
27 }
28
29 fn with_name(&self, name: String) -> Self {
30 let mut meta = (*self.meta).clone();
31 meta.inner.name = name;
32 Self {
33 meta: Arc::new(meta),
34 }
35 }
36
37 fn with_label(&self, label: MetricLabel) -> Self {
38 let mut meta = (*self.meta).clone();
39 meta.inner.label = Some(label);
40 Self {
41 meta: Arc::new(meta),
42 }
43 }
44}
45
46impl CounterMetric {
51 pub fn new(meta: CommonMetricData) -> Self {
53 Self {
54 meta: Arc::new(meta.into()),
55 }
56 }
57
58 #[doc(hidden)]
60 pub fn add_sync(&self, glean: &Glean, amount: i32) {
61 if !self.should_record(glean) {
62 return;
63 }
64
65 match amount.cmp(&0) {
66 Ordering::Less => {
67 record_error(
68 glean,
69 &self.meta,
70 ErrorType::InvalidValue,
71 format!("Added negative value {}", amount),
72 None,
73 );
74 return;
75 }
76 Ordering::Equal => {
77 return;
79 }
80 Ordering::Greater => (),
81 };
82
83 if let Some(storage) = glean.storage_opt() {
89 storage.record_with(glean, &self.meta, |old_value| match old_value {
90 Some(Metric::Counter(old_value)) => {
91 Metric::Counter(old_value.saturating_add(amount))
92 }
93 _ => Metric::Counter(amount),
94 })
95 } else {
96 log::warn!(
97 "Couldn't get storage. Can't record counter '{}'.",
98 self.meta.base_identifier()
99 );
100 }
101 }
102
103 pub fn add(&self, amount: i32) {
113 let metric = self.clone();
114 crate::launch_with_glean(move |glean| metric.add_sync(glean, amount))
115 }
116
117 #[doc(hidden)]
119 pub fn get_value<'a, S: Into<Option<&'a str>>>(
120 &self,
121 glean: &Glean,
122 ping_name: S,
123 ) -> Option<i32> {
124 let queried_ping_name = ping_name
125 .into()
126 .unwrap_or_else(|| &self.meta().inner.send_in_pings[0]);
127
128 match glean.storage().get_metric(self.meta(), queried_ping_name) {
129 Some(Metric::Counter(i)) => Some(i),
130 _ => None,
131 }
132 }
133
134 pub fn test_get_num_recorded_errors(&self, error: ErrorType) -> i32 {
146 crate::block_on_dispatcher();
147
148 crate::core::with_glean(|glean| {
149 test_get_num_recorded_errors(glean, self.meta(), error).unwrap_or(0)
150 })
151 }
152}
153
154impl TestGetValue for CounterMetric {
155 type Output = i32;
156
157 fn test_get_value(&self, ping_name: Option<String>) -> Option<i32> {
172 crate::block_on_dispatcher();
173 crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref()))
174 }
175}