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}