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 if self.meta().in_session() && !glean.session_manager().is_sampled_in() {
237 return false;
238 }
239
240 let disabled_field = self.meta().disabled.load(Ordering::Relaxed);
243 let epoch = disabled_field >> 4;
245 let disabled = disabled_field & 0xF;
247 let remote_settings_epoch = glean.remote_settings_epoch.load(Ordering::Acquire);
250 if epoch == remote_settings_epoch {
251 return disabled == 0;
252 }
253 let remote_settings_config = &glean.remote_settings_config.lock().unwrap();
256 let current_disabled = {
258 let base_id = self.meta().base_identifier();
259 let identifier = base_id
260 .split_once('/')
261 .map(|split| split.0)
262 .unwrap_or(&base_id);
263 if !remote_settings_config.metrics_enabled.is_empty() {
268 if let Some(is_enabled) = remote_settings_config.metrics_enabled.get(identifier) {
269 u8::from(!*is_enabled)
270 } else {
271 u8::from(self.meta().inner.disabled)
272 }
273 } else {
274 u8::from(self.meta().inner.disabled)
275 }
276 };
277
278 let new_disabled = (remote_settings_epoch << 4) | (current_disabled & 0xF);
280 self.meta().disabled.store(new_disabled, Ordering::Relaxed);
281
282 current_disabled == 0
284 }
285}
286
287pub trait MetricIdentifier<'a> {
290 fn get_identifiers(&'a self) -> (&'a str, &'a str, Option<&'a str>);
292}
293
294pub trait TestGetValue {
296 type Output;
298
299 fn test_get_value(&self, ping_name: Option<String>) -> Option<Self::Output>;
314}
315
316impl<'a, T> MetricIdentifier<'a> for T
319where
320 T: MetricType,
321{
322 fn get_identifiers(&'a self) -> (&'a str, &'a str, Option<&'a str>) {
323 let meta = &self.meta().inner;
324 (&meta.category, &meta.name, meta.dynamic_label.as_deref())
325 }
326}
327
328impl Metric {
329 pub fn ping_section(&self) -> &'static str {
334 match self {
335 Metric::Boolean(_) => "boolean",
336 Metric::Counter(_) => "counter",
337 Metric::CustomDistributionExponential(_) => "custom_distribution",
339 Metric::CustomDistributionLinear(_) => "custom_distribution",
340 Metric::Datetime(_, _) => "datetime",
341 Metric::Experiment(_) => panic!("Experiments should not be serialized through this"),
342 Metric::Quantity(_) => "quantity",
343 Metric::Rate(..) => "rate",
344 Metric::String(_) => "string",
345 Metric::StringList(_) => "string_list",
346 Metric::Timespan(..) => "timespan",
347 Metric::TimingDistribution(_) => "timing_distribution",
348 Metric::Url(_) => "url",
349 Metric::Uuid(_) => "uuid",
350 Metric::MemoryDistribution(_) => "memory_distribution",
351 Metric::Jwe(_) => "jwe",
352 Metric::Text(_) => "text",
353 Metric::Object(_) => "object",
354 }
355 }
356
357 pub fn as_json(&self) -> JsonValue {
359 match self {
360 Metric::Boolean(b) => json!(b),
361 Metric::Counter(c) => json!(c),
362 Metric::CustomDistributionExponential(hist) => {
363 json!(custom_distribution::snapshot(hist))
364 }
365 Metric::CustomDistributionLinear(hist) => json!(custom_distribution::snapshot(hist)),
366 Metric::Datetime(d, time_unit) => json!(get_iso_time_string(*d, *time_unit)),
367 Metric::Experiment(e) => e.as_json(),
368 Metric::Quantity(q) => json!(q),
369 Metric::Rate(num, den) => {
370 json!({"numerator": num, "denominator": den})
371 }
372 Metric::String(s) => json!(s),
373 Metric::StringList(v) => json!(v),
374 Metric::Timespan(time, time_unit) => {
375 json!({"value": time_unit.duration_convert(*time), "time_unit": time_unit})
376 }
377 Metric::TimingDistribution(hist) => json!(timing_distribution::snapshot(hist)),
378 Metric::Url(s) => json!(s),
379 Metric::Uuid(s) => json!(s),
380 Metric::MemoryDistribution(hist) => json!(memory_distribution::snapshot(hist)),
381 Metric::Jwe(s) => json!(s),
382 Metric::Text(s) => json!(s),
383 Metric::Object(s) => {
384 serde_json::from_str(s).expect("object storage should have been json")
385 }
386 }
387 }
388}
389
390macro_rules! impl_malloc_size_of_for_metric {
391 ($ty:ident) => {
392 impl ::malloc_size_of::MallocSizeOf for $ty {
393 fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
394 self.meta().size_of(ops)
397 }
398 }
399 };
400}
401
402impl_malloc_size_of_for_metric!(BooleanMetric);
403impl_malloc_size_of_for_metric!(CounterMetric);
404impl_malloc_size_of_for_metric!(CustomDistributionMetric);
405impl_malloc_size_of_for_metric!(DatetimeMetric);
406impl_malloc_size_of_for_metric!(DenominatorMetric);
407impl_malloc_size_of_for_metric!(EventMetric);
408impl_malloc_size_of_for_metric!(ExperimentMetric);
409impl_malloc_size_of_for_metric!(MemoryDistributionMetric);
410impl_malloc_size_of_for_metric!(NumeratorMetric);
411impl_malloc_size_of_for_metric!(ObjectMetric);
412impl_malloc_size_of_for_metric!(QuantityMetric);
413impl_malloc_size_of_for_metric!(RateMetric);
414impl_malloc_size_of_for_metric!(StringMetric);
415impl_malloc_size_of_for_metric!(StringListMetric);
416impl_malloc_size_of_for_metric!(TextMetric);
417impl_malloc_size_of_for_metric!(TimespanMetric);
418impl_malloc_size_of_for_metric!(UrlMetric);
419impl_malloc_size_of_for_metric!(UuidMetric);