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::util::truncate_string_at_boundary_with_error;
12use crate::Glean;
13use crate::{CommonMetricData, TestGetValue};
14
15const MAX_LIST_LENGTH: usize = 100;
17const MAX_STRING_LENGTH: usize = 100;
19
20#[derive(Clone, Debug)]
24pub struct StringListMetric {
25 meta: Arc<CommonMetricDataInternal>,
26}
27
28impl MetricType for StringListMetric {
29 fn meta(&self) -> &CommonMetricDataInternal {
30 &self.meta
31 }
32}
33
34impl StringListMetric {
39 pub fn new(meta: CommonMetricData) -> Self {
41 Self {
42 meta: Arc::new(meta.into()),
43 }
44 }
45
46 pub fn add(&self, value: String) {
56 let metric = self.clone();
57 crate::launch_with_glean(move |glean| metric.add_sync(glean, value))
58 }
59
60 #[doc(hidden)]
62 pub fn add_sync<S: Into<String>>(&self, glean: &Glean, value: S) {
63 if !self.should_record(glean) {
64 return;
65 }
66
67 let value =
68 truncate_string_at_boundary_with_error(glean, &self.meta, value, MAX_STRING_LENGTH);
69 let mut error = None;
70 glean
71 .storage()
72 .record_with(glean, &self.meta, |old_value| match old_value {
73 Some(Metric::StringList(mut old_value)) => {
74 if old_value.len() == MAX_LIST_LENGTH {
75 let msg = format!(
76 "String list length of {} exceeds maximum of {}",
77 old_value.len() + 1,
78 MAX_LIST_LENGTH
79 );
80 error = Some(msg);
81 } else {
82 old_value.push(value.clone());
83 }
84 Metric::StringList(old_value)
85 }
86 _ => Metric::StringList(vec![value.clone()]),
87 });
88
89 if let Some(msg) = error {
90 record_error(glean, &self.meta, ErrorType::InvalidValue, msg, None);
91 }
92 }
93
94 pub fn set(&self, values: Vec<String>) {
108 let metric = self.clone();
109 crate::launch_with_glean(move |glean| metric.set_sync(glean, values))
110 }
111
112 #[doc(hidden)]
114 pub fn set_sync(&self, glean: &Glean, value: Vec<String>) {
115 if !self.should_record(glean) {
116 return;
117 }
118
119 let value = if value.len() > MAX_LIST_LENGTH {
120 let msg = format!(
121 "StringList length {} exceeds maximum of {}",
122 value.len(),
123 MAX_LIST_LENGTH
124 );
125 record_error(glean, &self.meta, ErrorType::InvalidValue, msg, None);
126 value[0..MAX_LIST_LENGTH].to_vec()
127 } else {
128 value
129 };
130
131 let value = value
132 .into_iter()
133 .map(|elem| {
134 truncate_string_at_boundary_with_error(glean, &self.meta, elem, MAX_STRING_LENGTH)
135 })
136 .collect();
137
138 let value = Metric::StringList(value);
139 glean.storage().record(glean, &self.meta, &value);
140 }
141
142 #[doc(hidden)]
148 pub fn get_value<'a, S: Into<Option<&'a str>>>(
149 &self,
150 glean: &Glean,
151 ping_name: S,
152 ) -> Option<Vec<String>> {
153 let queried_ping_name = ping_name
154 .into()
155 .unwrap_or_else(|| &self.meta().inner.send_in_pings[0]);
156
157 match glean.storage().get_metric(self.meta(), queried_ping_name) {
158 Some(Metric::StringList(values)) => Some(values),
159 _ => None,
160 }
161 }
162
163 pub fn test_get_num_recorded_errors(&self, error: ErrorType) -> i32 {
175 crate::block_on_dispatcher();
176
177 crate::core::with_glean(|glean| {
178 test_get_num_recorded_errors(glean, self.meta(), error).unwrap_or(0)
179 })
180 }
181}
182
183impl TestGetValue for StringListMetric {
184 type Output = Vec<String>;
185
186 fn test_get_value(&self, ping_name: Option<String>) -> Option<Vec<String>> {
201 crate::block_on_dispatcher();
202 crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref()))
203 }
204}