// 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/.
use inherent::inherent;
usesuper::{
ErrorType, LabeledBooleanMetric, LabeledCounterMetric, LabeledCustomDistributionMetric,
LabeledMemoryDistributionMetric, LabeledMetricData, LabeledQuantityMetric, LabeledStringMetric,
LabeledTimingDistributionMetric, MetricId, SubMetricId,
}; usecrate::ipc::need_ipc; usecrate::metrics::__glean_metric_maps::submetric_maps; use std::borrow::Cow; use std::marker::PhantomData; use std::sync::Arc;
/// Sealed traits protect against downstream implementations. /// /// We wrap it in a private module that is inaccessible outside of this module. mod private { usesuper::{
need_ipc, submetric_maps, LabeledBooleanMetric, LabeledCounterMetric,
LabeledCustomDistributionMetric, LabeledMemoryDistributionMetric, LabeledQuantityMetric,
LabeledStringMetric, LabeledTimingDistributionMetric, MetricId, SubMetricId,
}; usecrate::private::labeled_timing_distribution::LabeledTimingDistributionMetricKind; usecrate::private::{
BooleanMetric, CounterMetric, CustomDistributionMetric, MemoryDistributionMetric, TimeUnit,
TimingDistributionMetric,
}; use std::sync::{atomic::Ordering, Arc};
/// The sealed trait. /// /// This allows us to define which FOG metrics can be used /// as labeled types. pubtrait Sealed { type GleanMetric: glean::private::AllowLabeled + Clone; fn from_glean_metric(
id: MetricId,
metric: &glean::private::LabeledMetric<Self::GleanMetric>,
label: &str,
permit_unordered_ipc: bool,
) -> (Arc<Self>, SubMetricId);
}
fn submetric_id_for(id: MetricId, label: &str) -> SubMetricId { let label_owned = label.to_string(); let tuple = (id, label_owned); letmut map = submetric_maps::LABELED_METRICS_TO_IDS
.write()
.expect("write lock of submetric ids was poisoned");
// `LabeledMetric<LabeledQuantityMetric>` is possible. // // See [Labeled Quantities](https://mozilla.github.io/glean/book/user/metrics/labeled_quantities.html). impl Sealed for LabeledQuantityMetric { type GleanMetric = glean::private::QuantityMetric; fn from_glean_metric(
id: MetricId,
metric: &glean::private::LabeledMetric<Self::GleanMetric>,
label: &str,
_permit_unordered_ipc: bool,
) -> (Arc<Self>, SubMetricId) { let submetric_id = submetric_id_for(id, label); letmut map = submetric_maps::QUANTITY_MAP
.write()
.expect("write lock of QUANTITY_MAP was poisoned"); let submetric = map.entry(submetric_id).or_insert_with(|| { let submetric = if need_ipc() { // TODO: Instrument this error.
LabeledQuantityMetric::Child(crate::private::quantity::QuantityMetricIpc)
} else {
LabeledQuantityMetric::Parent {
id: submetric_id.into(),
inner: metric.get(label),
}
};
Arc::new(submetric)
});
(Arc::clone(submetric), submetric_id)
}
}
}
/// Marker trait for metrics that can be nested inside a labeled metric. /// /// This trait is sealed and cannot be implemented for types outside this crate. pubtrait AllowLabeled: private::Sealed {}
// Implement the trait for everything we marked as allowed. impl<T> AllowLabeled for T where T: private::Sealed {}
/// A labeled metric. /// /// Labeled metrics allow to record multiple sub-metrics of the same type under different string labels. /// /// ## Example /// /// The following piece of code will be generated by `glean_parser`: /// /// ```rust,ignore /// use glean::metrics::{LabeledMetric, BooleanMetric, CommonMetricData, LabeledMetricData, Lifetime}; /// use once_cell::sync::Lazy; /// /// mod error { /// pub static seen_one: Lazy<LabeledMetric<BooleanMetric, DynamicLabel>> = Lazy::new(|| LabeledMetric::new(LabeledMetricData::Common{ cmd: CommonMetricData { /// name: "seen_one".into(), /// category: "error".into(), /// send_in_pings: vec!["ping".into()], /// disabled: false, /// lifetime: Lifetime::Ping, /// ..Default::default() /// }}, None)); /// } /// ``` /// /// It can then be used with: /// /// ```rust,ignore /// errro::seen_one.get("upload").set(true); /// ``` pubstruct LabeledMetric<T: AllowLabeled, E> { /// The metric ID of the underlying metric.
id: MetricId,
/// Wrapping the underlying core metric. /// /// We delegate all functionality to this and wrap it up again in our own metric type.
core: glean::private::LabeledMetric<T::GleanMetric>,
label_enum: PhantomData<E>,
/// Whether this labeled_* metric is permitted to perform non-commutative /// metric operations over unordered IPC.
permit_unordered_ipc: bool,
}
impl<T, E> LabeledMetric<T, E> where
T: AllowLabeled + Clone,
{ /// Create a new labeled metric from the given metric instance and optional list of labels. /// /// See [`get`](#method.get) for information on how static or dynamic labels are handled. pubfn new(
id: MetricId,
meta: LabeledMetricData,
labels: Option<Vec<Cow<'static, str>>>,
) -> LabeledMetric<T, E> { let core = glean::private::LabeledMetric::new(meta, labels);
LabeledMetric {
id,
core,
label_enum: PhantomData,
permit_unordered_ipc: false,
}
}
#[inherent] impl<U, E> glean::traits::Labeled<Arc<U>> for LabeledMetric<U, E> where
U: AllowLabeled + Clone,
{ /// Gets a specific metric for a given label. /// /// If a set of acceptable labels were specified in the `metrics.yaml` file, /// and the given label is not in the set, it will be recorded under the special `OTHER_LABEL` label. /// /// If a set of acceptable labels was not specified in the `metrics.yaml` file, /// only the first 16 unique labels will be used. /// After that, any additional labels will be recorded under the special `OTHER_LABEL` label. /// /// Labels must be `snake_case` and less than 30 characters. /// If an invalid label is used, the metric will be recorded in the special `OTHER_LABEL` label. pubfn get(&self, label: &str) -> Arc<U> {
U::from_glean_metric(self.id, &self.core, label, self.permit_unordered_ipc).0
}
/// **Exported for test purposes.** /// /// Gets the number of recorded errors for the given metric and error type. /// /// # Arguments /// /// * `error` - The type of error /// * `ping_name` - represents the optional name of the ping to retrieve the /// metric for. Defaults to the first value in `send_in_pings`. /// /// # Returns /// /// The number of errors reported. pubfn test_get_num_recorded_errors(&self, error: ErrorType) -> i32 { if need_ipc() {
panic!("Use of labeled metrics in IPC land not yet implemented!");
} else { self.core.test_get_num_recorded_errors(error)
}
}
}
#[cfg(test)] mod test { use once_cell::sync::Lazy;
assert_eq!( true,
metric.get("label1").test_get_value("test-ping").unwrap()
);
assert_eq!( false,
metric.get("label2").test_get_value("test-ping").unwrap()
); // The label not in the predefined set is recorded to the `other` bucket.
assert_eq!( true,
metric.get("__other__").test_get_value("test-ping").unwrap()
);
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.