// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! The different metric types supported by the Glean SDK to handle data.
use std::collections::HashMap; use std::sync::atomic::Ordering;
use chrono::{DateTime, FixedOffset}; use serde::{Deserialize, Serialize}; use serde_json::json; pubuse serde_json::Value as JsonValue;
mod boolean; mod counter; mod custom_distribution; mod datetime; mod denominator; mod event; mod experiment; pub(crate) mod labeled; mod memory_distribution; mod memory_unit; mod numerator; mod object; mod ping; mod quantity; mod rate; mod recorded_experiment; mod remote_settings_config; mod string; mod string_list; mod text; mod time_unit; mod timespan; mod timing_distribution; mod url; mod uuid;
/// A snapshot of all buckets and the accumulated sum of a distribution. // // Note: Be careful when changing this structure. // The serialized form ends up in the ping payload. // New fields might require to be skipped on serialization. #[derive(Debug, Serialize, PartialEq)] pubstruct DistributionData { /// A map containig the bucket index mapped to the accumulated count. /// /// This can contain buckets with a count of `0`. pub values: HashMap<i64, i64>,
/// The accumulated sum of all the samples in the distribution. pub sum: i64,
/// The total number of entries in the distribution. #[serde(skip)] pub count: i64,
}
/// The available metrics. /// /// This is the in-memory and persisted layout of a metric. /// /// ## Note /// /// The order of metrics in this enum is important, as it is used for serialization. /// Do not reorder the variants. /// /// **Any new metric must be added at the end.** #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pubenum Metric { /// A boolean metric. See [`BooleanMetric`] for more information.
Boolean(bool), /// A counter metric. See [`CounterMetric`] for more information.
Counter(i32), /// A custom distribution with precomputed exponential bucketing. /// See [`CustomDistributionMetric`] for more information.
CustomDistributionExponential(Histogram<PrecomputedExponential>), /// A custom distribution with precomputed linear bucketing. /// See [`CustomDistributionMetric`] for more information.
CustomDistributionLinear(Histogram<PrecomputedLinear>), /// A datetime metric. See [`DatetimeMetric`] for more information.
Datetime(DateTime<FixedOffset>, TimeUnit), /// An experiment metric. See `ExperimentMetric` for more information.
Experiment(recorded_experiment::RecordedExperiment), /// A quantity metric. See [`QuantityMetric`] for more information.
Quantity(i64), /// A string metric. See [`StringMetric`] for more information.
String(String), /// A string list metric. See [`StringListMetric`] for more information.
StringList(Vec<String>), /// A UUID metric. See [`UuidMetric`] for more information.
Uuid(String), /// A timespan metric. See [`TimespanMetric`] for more information.
Timespan(std::time::Duration, TimeUnit), /// A timing distribution. See [`TimingDistributionMetric`] for more information.
TimingDistribution(Histogram<Functional>), /// A memory distribution. See [`MemoryDistributionMetric`] for more information.
MemoryDistribution(Histogram<Functional>), /// **DEPRECATED**: A JWE metric.. /// Note: This variant MUST NOT be removed to avoid backwards-incompatible changes to the /// serialization. This type has no underlying implementation anymore.
Jwe(String), /// A rate metric. See [`RateMetric`] for more information.
Rate(i32, i32), /// A URL metric. See [`UrlMetric`] for more information.
Url(String), /// A Text metric. See [`TextMetric`] for more information.
Text(String), /// An Object metric. See [`ObjectMetric`] for more information.
Object(String),
}
/// A [`MetricType`] describes common behavior across all metrics. pubtrait MetricType { /// Access the stored metadata fn meta(&self) -> &CommonMetricDataInternal;
/// Create a new metric from this with a new name. fn with_name(&self, _name: String) -> Self where Self: Sized,
{
unimplemented!()
}
/// Create a new metric from this with a specific label. fn with_dynamic_label(&self, _label: String) -> Self where Self: Sized,
{
unimplemented!()
}
/// Whether this metric should currently be recorded /// /// This depends on the metrics own state, as determined by its metadata, /// and whether upload is enabled on the Glean object. fn should_record(&self, glean: &Glean) -> bool { // Technically nothing prevents multiple calls to should_record() to run in parallel, // meaning both are reading self.meta().disabled and later writing it. In between it can // also read remote_settings_config, which also could be modified in between those 2 reads. // This means we could write the wrong remote_settings_epoch | current_disabled value. All in all // at worst we would see that metric enabled/disabled wrongly once. // But since everything is tunneled through the dispatcher, this should never ever happen.
// Get the current disabled field from the metric metadata, including // the encoded remote_settings epoch let disabled_field = self.meta().disabled.load(Ordering::Relaxed); // Grab the epoch from the upper nibble let epoch = disabled_field >> 4; // Get the disabled flag from the lower nibble let disabled = disabled_field & 0xF; // Get the current remote_settings epoch to see if we need to bother with the // more expensive HashMap lookup let remote_settings_epoch = glean.remote_settings_epoch.load(Ordering::Acquire); if epoch == remote_settings_epoch { return disabled == 0;
} // The epoch's didn't match so we need to look up the disabled flag // by the base_identifier from the in-memory HashMap let remote_settings_config = &glean.remote_settings_config.lock().unwrap(); // Get the value from the remote configuration if it is there, otherwise return the default value. let current_disabled = { let base_id = self.meta().base_identifier(); let identifier = base_id
.split_once('/')
.map(|split| split.0)
.unwrap_or(&base_id); // NOTE: The `!` preceding the `*is_enabled` is important for inverting the logic since the // underlying property in the metrics.yaml is `disabled` and the outward API is treating it as // if it were `enabled` to make it easier to understand.
// Re-encode the epoch and enabled status and update the metadata let new_disabled = (remote_settings_epoch << 4) | (current_disabled & 0xF); self.meta().disabled.store(new_disabled, Ordering::Relaxed);
// Return a boolean indicating whether or not the metric should be recorded
current_disabled == 0
}
}
impl Metric { /// Gets the ping section the metric fits into. /// /// This determines the section of the ping to place the metric data in when /// assembling the ping payload. pubfn ping_section(&self) -> &'static str { matchself {
Metric::Boolean(_) => "boolean",
Metric::Counter(_) => "counter", // Custom distributions are in the same section, no matter what bucketing.
Metric::CustomDistributionExponential(_) => "custom_distribution",
Metric::CustomDistributionLinear(_) => "custom_distribution",
Metric::Datetime(_, _) => "datetime",
Metric::Experiment(_) => panic!("Experiments should not be serialized through this"),
Metric::Quantity(_) => "quantity",
Metric::Rate(..) => "rate",
Metric::String(_) => "string",
Metric::StringList(_) => "string_list",
Metric::Timespan(..) => "timespan",
Metric::TimingDistribution(_) => "timing_distribution",
Metric::Url(_) => "url",
Metric::Uuid(_) => "uuid",
Metric::MemoryDistribution(_) => "memory_distribution",
Metric::Jwe(_) => "jwe",
Metric::Text(_) => "text",
Metric::Object(_) => "object",
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.