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