1use std::collections::HashMap;
8use std::sync::atomic::Ordering;
9
10use chrono::{DateTime, FixedOffset};
11use serde::{Deserialize, Serialize};
12use serde_json::json;
13pub use serde_json::Value as JsonValue;
14
15mod boolean;
16mod counter;
17mod custom_distribution;
18mod datetime;
19mod denominator;
20mod event;
21mod experiment;
22pub(crate) mod labeled;
23mod memory_distribution;
24mod memory_unit;
25mod numerator;
26mod object;
27mod ping;
28mod quantity;
29mod rate;
30mod recorded_experiment;
31mod remote_settings_config;
32mod string;
33mod string_list;
34mod text;
35mod time_unit;
36mod timespan;
37mod timing_distribution;
38mod url;
39mod uuid;
40
41use crate::common_metric_data::CommonMetricDataInternal;
42pub use crate::event_database::RecordedEvent;
43use crate::histogram::{Functional, Histogram, PrecomputedExponential, PrecomputedLinear};
44pub use crate::metrics::datetime::Datetime;
45use crate::util::get_iso_time_string;
46use crate::Glean;
47
48pub use self::boolean::BooleanMetric;
49pub use self::counter::CounterMetric;
50pub use self::custom_distribution::{CustomDistributionMetric, LocalCustomDistribution};
51pub use self::datetime::DatetimeMetric;
52pub use self::denominator::DenominatorMetric;
53pub use self::event::EventMetric;
54pub(crate) use self::experiment::ExperimentMetric;
55pub use self::labeled::{
56 LabeledBoolean, LabeledCounter, LabeledCustomDistribution, LabeledMemoryDistribution,
57 LabeledMetric, LabeledQuantity, LabeledString, LabeledTimingDistribution,
58};
59pub use self::memory_distribution::{LocalMemoryDistribution, MemoryDistributionMetric};
60pub use self::memory_unit::MemoryUnit;
61pub use self::numerator::NumeratorMetric;
62pub use self::object::ObjectMetric;
63pub use self::ping::PingType;
64pub use self::quantity::QuantityMetric;
65pub use self::rate::{Rate, RateMetric};
66pub use self::string::StringMetric;
67pub use self::string_list::StringListMetric;
68pub use self::text::TextMetric;
69pub use self::time_unit::TimeUnit;
70pub use self::timespan::TimespanMetric;
71pub use self::timing_distribution::LocalTimingDistribution;
72pub use self::timing_distribution::TimerId;
73pub use self::timing_distribution::TimingDistributionMetric;
74pub use self::url::UrlMetric;
75pub use self::uuid::UuidMetric;
76pub use crate::histogram::HistogramType;
77pub use recorded_experiment::RecordedExperiment;
78
79pub use self::remote_settings_config::RemoteSettingsConfig;
80
81#[derive(Debug, Serialize, PartialEq)]
87pub struct DistributionData {
88 pub values: HashMap<i64, i64>,
92
93 pub sum: i64,
95
96 #[serde(skip)]
98 pub count: i64,
99}
100
101#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
112pub enum Metric {
113 Boolean(bool),
115 Counter(i32),
117 CustomDistributionExponential(Histogram<PrecomputedExponential>),
120 CustomDistributionLinear(Histogram<PrecomputedLinear>),
123 Datetime(DateTime<FixedOffset>, TimeUnit),
125 Experiment(recorded_experiment::RecordedExperiment),
127 Quantity(i64),
129 String(String),
131 StringList(Vec<String>),
133 Uuid(String),
135 Timespan(std::time::Duration, TimeUnit),
137 TimingDistribution(Histogram<Functional>),
139 MemoryDistribution(Histogram<Functional>),
141 Jwe(String),
145 Rate(i32, i32),
147 Url(String),
149 Text(String),
151 Object(String),
153}
154
155pub trait MetricType {
157 fn meta(&self) -> &CommonMetricDataInternal;
159
160 fn with_name(&self, _name: String) -> Self
162 where
163 Self: Sized,
164 {
165 unimplemented!()
166 }
167
168 fn with_dynamic_label(&self, _label: String) -> Self
170 where
171 Self: Sized,
172 {
173 unimplemented!()
174 }
175
176 fn should_record(&self, glean: &Glean) -> bool {
181 let disabled_field = self.meta().disabled.load(Ordering::Relaxed);
191 let epoch = disabled_field >> 4;
193 let disabled = disabled_field & 0xF;
195 let remote_settings_epoch = glean.remote_settings_epoch.load(Ordering::Acquire);
198 if epoch == remote_settings_epoch {
199 return disabled == 0;
200 }
201 let remote_settings_config = &glean.remote_settings_config.lock().unwrap();
204 let current_disabled = {
206 let base_id = self.meta().base_identifier();
207 let identifier = base_id
208 .split_once('/')
209 .map(|split| split.0)
210 .unwrap_or(&base_id);
211 if !remote_settings_config.metrics_enabled.is_empty() {
216 if let Some(is_enabled) = remote_settings_config.metrics_enabled.get(identifier) {
217 u8::from(!*is_enabled)
218 } else {
219 u8::from(self.meta().inner.disabled)
220 }
221 } else {
222 u8::from(self.meta().inner.disabled)
223 }
224 };
225
226 let new_disabled = (remote_settings_epoch << 4) | (current_disabled & 0xF);
228 self.meta().disabled.store(new_disabled, Ordering::Relaxed);
229
230 current_disabled == 0
232 }
233}
234
235pub trait MetricIdentifier<'a> {
238 fn get_identifiers(&'a self) -> (&'a str, &'a str, Option<&'a str>);
240}
241
242impl<'a, T> MetricIdentifier<'a> for T
245where
246 T: MetricType,
247{
248 fn get_identifiers(&'a self) -> (&'a str, &'a str, Option<&'a str>) {
249 let meta = &self.meta().inner;
250 (&meta.category, &meta.name, meta.dynamic_label.as_deref())
251 }
252}
253
254impl Metric {
255 pub fn ping_section(&self) -> &'static str {
260 match self {
261 Metric::Boolean(_) => "boolean",
262 Metric::Counter(_) => "counter",
263 Metric::CustomDistributionExponential(_) => "custom_distribution",
265 Metric::CustomDistributionLinear(_) => "custom_distribution",
266 Metric::Datetime(_, _) => "datetime",
267 Metric::Experiment(_) => panic!("Experiments should not be serialized through this"),
268 Metric::Quantity(_) => "quantity",
269 Metric::Rate(..) => "rate",
270 Metric::String(_) => "string",
271 Metric::StringList(_) => "string_list",
272 Metric::Timespan(..) => "timespan",
273 Metric::TimingDistribution(_) => "timing_distribution",
274 Metric::Url(_) => "url",
275 Metric::Uuid(_) => "uuid",
276 Metric::MemoryDistribution(_) => "memory_distribution",
277 Metric::Jwe(_) => "jwe",
278 Metric::Text(_) => "text",
279 Metric::Object(_) => "object",
280 }
281 }
282
283 pub fn as_json(&self) -> JsonValue {
285 match self {
286 Metric::Boolean(b) => json!(b),
287 Metric::Counter(c) => json!(c),
288 Metric::CustomDistributionExponential(hist) => {
289 json!(custom_distribution::snapshot(hist))
290 }
291 Metric::CustomDistributionLinear(hist) => json!(custom_distribution::snapshot(hist)),
292 Metric::Datetime(d, time_unit) => json!(get_iso_time_string(*d, *time_unit)),
293 Metric::Experiment(e) => e.as_json(),
294 Metric::Quantity(q) => json!(q),
295 Metric::Rate(num, den) => {
296 json!({"numerator": num, "denominator": den})
297 }
298 Metric::String(s) => json!(s),
299 Metric::StringList(v) => json!(v),
300 Metric::Timespan(time, time_unit) => {
301 json!({"value": time_unit.duration_convert(*time), "time_unit": time_unit})
302 }
303 Metric::TimingDistribution(hist) => json!(timing_distribution::snapshot(hist)),
304 Metric::Url(s) => json!(s),
305 Metric::Uuid(s) => json!(s),
306 Metric::MemoryDistribution(hist) => json!(memory_distribution::snapshot(hist)),
307 Metric::Jwe(s) => json!(s),
308 Metric::Text(s) => json!(s),
309 Metric::Object(s) => {
310 serde_json::from_str(s).expect("object storage should have been json")
311 }
312 }
313 }
314}