1use std::collections::HashMap;
8use std::sync::atomic::Ordering;
9
10use chrono::{DateTime, FixedOffset};
11use malloc_size_of::MallocSizeOf;
12use serde::{Deserialize, Serialize};
13use serde_json::json;
14pub use serde_json::Value as JsonValue;
15
16mod boolean;
17mod counter;
18mod custom_distribution;
19mod datetime;
20mod denominator;
21pub(crate) mod dual_labeled_counter;
22mod event;
23mod experiment;
24pub(crate) mod labeled;
25mod memory_distribution;
26mod memory_unit;
27mod numerator;
28mod object;
29mod ping;
30mod quantity;
31mod rate;
32mod recorded_experiment;
33mod remote_settings_config;
34mod string;
35mod string_list;
36mod text;
37mod time_unit;
38mod timespan;
39mod timing_distribution;
40mod url;
41mod uuid;
42
43use crate::common_metric_data::CommonMetricDataInternal;
44pub use crate::common_metric_data::DynamicLabelType;
45pub use crate::event_database::RecordedEvent;
46use crate::histogram::{Functional, Histogram, PrecomputedExponential, PrecomputedLinear};
47pub use crate::metrics::datetime::Datetime;
48use crate::util::get_iso_time_string;
49use crate::Glean;
50
51pub use self::boolean::BooleanMetric;
52pub use self::counter::CounterMetric;
53pub use self::custom_distribution::{CustomDistributionMetric, LocalCustomDistribution};
54pub use self::datetime::DatetimeMetric;
55pub use self::denominator::DenominatorMetric;
56pub use self::dual_labeled_counter::DualLabeledCounterMetric;
57pub use self::event::EventMetric;
58pub(crate) use self::experiment::ExperimentMetric;
59pub use self::labeled::{
60 LabeledBoolean, LabeledCounter, LabeledCustomDistribution, LabeledMemoryDistribution,
61 LabeledMetric, LabeledMetricData, LabeledQuantity, LabeledString, LabeledTimingDistribution,
62};
63pub use self::memory_distribution::{LocalMemoryDistribution, MemoryDistributionMetric};
64pub use self::memory_unit::MemoryUnit;
65pub use self::numerator::NumeratorMetric;
66pub use self::object::ObjectMetric;
67pub use self::ping::PingType;
68pub use self::quantity::QuantityMetric;
69pub use self::rate::{Rate, RateMetric};
70pub use self::string::StringMetric;
71pub use self::string_list::StringListMetric;
72pub use self::text::TextMetric;
73pub use self::time_unit::TimeUnit;
74pub use self::timespan::TimespanMetric;
75pub use self::timing_distribution::LocalTimingDistribution;
76pub use self::timing_distribution::TimerId;
77pub use self::timing_distribution::TimingDistributionMetric;
78pub use self::url::UrlMetric;
79pub use self::uuid::UuidMetric;
80pub use crate::histogram::HistogramType;
81pub use recorded_experiment::RecordedExperiment;
82
83pub use self::remote_settings_config::RemoteSettingsConfig;
84
85#[derive(Debug, Serialize, PartialEq)]
91pub struct DistributionData {
92 pub values: HashMap<i64, i64>,
96
97 pub sum: i64,
99
100 #[serde(skip)]
102 pub count: i64,
103}
104
105#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
116pub enum Metric {
117 Boolean(bool),
119 Counter(i32),
121 CustomDistributionExponential(Histogram<PrecomputedExponential>),
124 CustomDistributionLinear(Histogram<PrecomputedLinear>),
127 Datetime(DateTime<FixedOffset>, TimeUnit),
129 Experiment(recorded_experiment::RecordedExperiment),
131 Quantity(i64),
133 String(String),
135 StringList(Vec<String>),
137 Uuid(String),
139 Timespan(std::time::Duration, TimeUnit),
141 TimingDistribution(Histogram<Functional>),
143 MemoryDistribution(Histogram<Functional>),
145 Jwe(String),
149 Rate(i32, i32),
151 Url(String),
153 Text(String),
155 Object(String),
157}
158
159impl MallocSizeOf for Metric {
160 fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
161 match self {
162 Metric::Boolean(m) => m.size_of(ops),
163 Metric::Counter(m) => m.size_of(ops),
164 Metric::CustomDistributionExponential(m) => m.size_of(ops),
166 Metric::CustomDistributionLinear(m) => m.size_of(ops),
167 Metric::Datetime(_a, b) => b.size_of(ops),
168 Metric::Experiment(m) => m.size_of(ops),
169 Metric::Quantity(m) => m.size_of(ops),
170 Metric::Rate(a, b) => a.size_of(ops) + b.size_of(ops),
171 Metric::String(m) => m.size_of(ops),
172 Metric::StringList(m) => m.size_of(ops),
173 Metric::Timespan(a, b) => a.size_of(ops) + b.size_of(ops),
174 Metric::TimingDistribution(m) => m.size_of(ops),
175 Metric::Url(m) => m.size_of(ops),
176 Metric::Uuid(m) => m.size_of(ops),
177 Metric::MemoryDistribution(m) => m.size_of(ops),
178 Metric::Jwe(m) => m.size_of(ops),
179 Metric::Text(m) => m.size_of(ops),
180 Metric::Object(m) => m.size_of(ops),
181 }
182 }
183}
184
185pub trait MetricType {
187 fn meta(&self) -> &CommonMetricDataInternal;
189
190 fn with_name(&self, _name: String) -> Self
192 where
193 Self: Sized,
194 {
195 unimplemented!()
196 }
197
198 fn with_dynamic_label(&self, _label: DynamicLabelType) -> Self
200 where
201 Self: Sized,
202 {
203 unimplemented!()
204 }
205
206 fn should_record(&self, glean: &Glean) -> bool {
211 let disabled_field = self.meta().disabled.load(Ordering::Relaxed);
221 let epoch = disabled_field >> 4;
223 let disabled = disabled_field & 0xF;
225 let remote_settings_epoch = glean.remote_settings_epoch.load(Ordering::Acquire);
228 if epoch == remote_settings_epoch {
229 return disabled == 0;
230 }
231 let remote_settings_config = &glean.remote_settings_config.lock().unwrap();
234 let current_disabled = {
236 let base_id = self.meta().base_identifier();
237 let identifier = base_id
238 .split_once('/')
239 .map(|split| split.0)
240 .unwrap_or(&base_id);
241 if !remote_settings_config.metrics_enabled.is_empty() {
246 if let Some(is_enabled) = remote_settings_config.metrics_enabled.get(identifier) {
247 u8::from(!*is_enabled)
248 } else {
249 u8::from(self.meta().inner.disabled)
250 }
251 } else {
252 u8::from(self.meta().inner.disabled)
253 }
254 };
255
256 let new_disabled = (remote_settings_epoch << 4) | (current_disabled & 0xF);
258 self.meta().disabled.store(new_disabled, Ordering::Relaxed);
259
260 current_disabled == 0
262 }
263}
264
265pub trait MetricIdentifier<'a> {
268 fn get_identifiers(&'a self) -> (&'a str, &'a str, Option<&'a str>);
270}
271
272pub trait TestGetValue<T> {
274 fn test_get_value(&self, ping_name: Option<String>) -> Option<T>;
289}
290
291impl<'a, T> MetricIdentifier<'a> for T
294where
295 T: MetricType,
296{
297 fn get_identifiers(&'a self) -> (&'a str, &'a str, Option<&'a str>) {
298 let meta = &self.meta().inner;
299 (&meta.category, &meta.name, meta.dynamic_label.as_deref())
300 }
301}
302
303impl Metric {
304 pub fn ping_section(&self) -> &'static str {
309 match self {
310 Metric::Boolean(_) => "boolean",
311 Metric::Counter(_) => "counter",
312 Metric::CustomDistributionExponential(_) => "custom_distribution",
314 Metric::CustomDistributionLinear(_) => "custom_distribution",
315 Metric::Datetime(_, _) => "datetime",
316 Metric::Experiment(_) => panic!("Experiments should not be serialized through this"),
317 Metric::Quantity(_) => "quantity",
318 Metric::Rate(..) => "rate",
319 Metric::String(_) => "string",
320 Metric::StringList(_) => "string_list",
321 Metric::Timespan(..) => "timespan",
322 Metric::TimingDistribution(_) => "timing_distribution",
323 Metric::Url(_) => "url",
324 Metric::Uuid(_) => "uuid",
325 Metric::MemoryDistribution(_) => "memory_distribution",
326 Metric::Jwe(_) => "jwe",
327 Metric::Text(_) => "text",
328 Metric::Object(_) => "object",
329 }
330 }
331
332 pub fn as_json(&self) -> JsonValue {
334 match self {
335 Metric::Boolean(b) => json!(b),
336 Metric::Counter(c) => json!(c),
337 Metric::CustomDistributionExponential(hist) => {
338 json!(custom_distribution::snapshot(hist))
339 }
340 Metric::CustomDistributionLinear(hist) => json!(custom_distribution::snapshot(hist)),
341 Metric::Datetime(d, time_unit) => json!(get_iso_time_string(*d, *time_unit)),
342 Metric::Experiment(e) => e.as_json(),
343 Metric::Quantity(q) => json!(q),
344 Metric::Rate(num, den) => {
345 json!({"numerator": num, "denominator": den})
346 }
347 Metric::String(s) => json!(s),
348 Metric::StringList(v) => json!(v),
349 Metric::Timespan(time, time_unit) => {
350 json!({"value": time_unit.duration_convert(*time), "time_unit": time_unit})
351 }
352 Metric::TimingDistribution(hist) => json!(timing_distribution::snapshot(hist)),
353 Metric::Url(s) => json!(s),
354 Metric::Uuid(s) => json!(s),
355 Metric::MemoryDistribution(hist) => json!(memory_distribution::snapshot(hist)),
356 Metric::Jwe(s) => json!(s),
357 Metric::Text(s) => json!(s),
358 Metric::Object(s) => {
359 serde_json::from_str(s).expect("object storage should have been json")
360 }
361 }
362 }
363}
364
365macro_rules! impl_malloc_size_of_for_metric {
366 ($ty:ident) => {
367 impl ::malloc_size_of::MallocSizeOf for $ty {
368 fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
369 self.meta().size_of(ops)
372 }
373 }
374 };
375}
376
377impl_malloc_size_of_for_metric!(BooleanMetric);
378impl_malloc_size_of_for_metric!(CounterMetric);
379impl_malloc_size_of_for_metric!(CustomDistributionMetric);
380impl_malloc_size_of_for_metric!(DatetimeMetric);
381impl_malloc_size_of_for_metric!(DenominatorMetric);
382impl_malloc_size_of_for_metric!(EventMetric);
383impl_malloc_size_of_for_metric!(ExperimentMetric);
384impl_malloc_size_of_for_metric!(MemoryDistributionMetric);
385impl_malloc_size_of_for_metric!(NumeratorMetric);
386impl_malloc_size_of_for_metric!(ObjectMetric);
387impl_malloc_size_of_for_metric!(QuantityMetric);
388impl_malloc_size_of_for_metric!(RateMetric);
389impl_malloc_size_of_for_metric!(StringMetric);
390impl_malloc_size_of_for_metric!(StringListMetric);
391impl_malloc_size_of_for_metric!(TextMetric);
392impl_malloc_size_of_for_metric!(TimespanMetric);
393impl_malloc_size_of_for_metric!(UrlMetric);
394impl_malloc_size_of_for_metric!(UuidMetric);