glean_core/metrics/
string_list.rs1use std::sync::Arc;
6
7use crate::common_metric_data::CommonMetricDataInternal;
8use crate::error_recording::{record_error, test_get_num_recorded_errors, ErrorType};
9use crate::metrics::Metric;
10use crate::metrics::MetricType;
11use crate::storage::StorageManager;
12use crate::util::truncate_string_at_boundary_with_error;
13use crate::Glean;
14use crate::{CommonMetricData, TestGetValue};
15
16const MAX_LIST_LENGTH: usize = 100;
18const MAX_STRING_LENGTH: usize = 100;
20
21#[derive(Clone, Debug)]
25pub struct StringListMetric {
26 meta: Arc<CommonMetricDataInternal>,
27}
28
29impl MetricType for StringListMetric {
30 fn meta(&self) -> &CommonMetricDataInternal {
31 &self.meta
32 }
33}
34
35impl StringListMetric {
40 pub fn new(meta: CommonMetricData) -> Self {
42 Self {
43 meta: Arc::new(meta.into()),
44 }
45 }
46
47 pub fn add(&self, value: String) {
57 let metric = self.clone();
58 crate::launch_with_glean(move |glean| metric.add_sync(glean, value))
59 }
60
61 #[doc(hidden)]
63 pub fn add_sync<S: Into<String>>(&self, glean: &Glean, value: S) {
64 if !self.should_record(glean) {
65 return;
66 }
67
68 let value =
69 truncate_string_at_boundary_with_error(glean, &self.meta, value, MAX_STRING_LENGTH);
70 let mut error = None;
71 glean
72 .storage()
73 .record_with(glean, &self.meta, |old_value| match old_value {
74 Some(Metric::StringList(mut old_value)) => {
75 if old_value.len() == MAX_LIST_LENGTH {
76 let msg = format!(
77 "String list length of {} exceeds maximum of {}",
78 old_value.len() + 1,
79 MAX_LIST_LENGTH
80 );
81 error = Some(msg);
82 } else {
83 old_value.push(value.clone());
84 }
85 Metric::StringList(old_value)
86 }
87 _ => Metric::StringList(vec![value.clone()]),
88 });
89
90 if let Some(msg) = error {
91 record_error(glean, &self.meta, ErrorType::InvalidValue, msg, None);
92 }
93 }
94
95 pub fn set(&self, values: Vec<String>) {
109 let metric = self.clone();
110 crate::launch_with_glean(move |glean| metric.set_sync(glean, values))
111 }
112
113 #[doc(hidden)]
115 pub fn set_sync(&self, glean: &Glean, value: Vec<String>) {
116 if !self.should_record(glean) {
117 return;
118 }
119
120 let value = if value.len() > MAX_LIST_LENGTH {
121 let msg = format!(
122 "StringList length {} exceeds maximum of {}",
123 value.len(),
124 MAX_LIST_LENGTH
125 );
126 record_error(glean, &self.meta, ErrorType::InvalidValue, msg, None);
127 value[0..MAX_LIST_LENGTH].to_vec()
128 } else {
129 value
130 };
131
132 let value = value
133 .into_iter()
134 .map(|elem| {
135 truncate_string_at_boundary_with_error(glean, &self.meta, elem, MAX_STRING_LENGTH)
136 })
137 .collect();
138
139 let value = Metric::StringList(value);
140 glean.storage().record(glean, &self.meta, &value);
141 }
142
143 #[doc(hidden)]
149 pub fn get_value<'a, S: Into<Option<&'a str>>>(
150 &self,
151 glean: &Glean,
152 ping_name: S,
153 ) -> Option<Vec<String>> {
154 let queried_ping_name = ping_name
155 .into()
156 .unwrap_or_else(|| &self.meta().inner.send_in_pings[0]);
157
158 match StorageManager.snapshot_metric_for_test(
159 glean.storage(),
160 queried_ping_name,
161 &self.meta.identifier(glean),
162 self.meta.inner.lifetime,
163 ) {
164 Some(Metric::StringList(values)) => Some(values),
165 _ => None,
166 }
167 }
168
169 pub fn test_get_num_recorded_errors(&self, error: ErrorType) -> i32 {
181 crate::block_on_dispatcher();
182
183 crate::core::with_glean(|glean| {
184 test_get_num_recorded_errors(glean, self.meta(), error).unwrap_or(0)
185 })
186 }
187}
188
189impl TestGetValue<Vec<String>> for StringListMetric {
190 fn test_get_value(&self, ping_name: Option<String>) -> Option<Vec<String>> {
205 crate::block_on_dispatcher();
206 crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref()))
207 }
208}