зеркало из https://github.com/mozilla/glean.git
[RLB] Re-implement events
Allow recording an event with a supplied timestamp
This commit is contained in:
Родитель
37830f89f3
Коммит
db2d5c7964
|
@ -0,0 +1,165 @@
|
|||
// 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;
|
||||
use std::{collections::HashMap, marker::PhantomData};
|
||||
|
||||
use glean_core::traits;
|
||||
|
||||
use crate::{ErrorType, RecordedEvent};
|
||||
|
||||
pub use glean_core::traits::NoExtraKeys;
|
||||
|
||||
// We need to wrap the glean-core type: otherwise if we try to implement
|
||||
// the trait for the metric in `glean_core::metrics` we hit error[E0117]:
|
||||
// only traits defined in the current crate can be implemented for arbitrary
|
||||
// types.
|
||||
|
||||
/// Developer-facing API for recording event metrics.
|
||||
///
|
||||
/// Instances of this class type are automatically generated by the parsers
|
||||
/// at build time, allowing developers to record values that were previously
|
||||
/// registered in the metrics.yaml file.
|
||||
#[derive(Clone)]
|
||||
pub struct EventMetric<K> {
|
||||
pub(crate) inner: glean_core::metrics::EventMetric,
|
||||
extra_keys: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K: traits::ExtraKeys> EventMetric<K> {
|
||||
/// The public constructor used by automatically generated metrics.
|
||||
pub fn new(meta: glean_core::CommonMetricData) -> Self {
|
||||
let allowed_extra_keys = K::ALLOWED_KEYS.iter().map(|s| s.to_string()).collect();
|
||||
let inner = glean_core::metrics::EventMetric::new(meta, allowed_extra_keys);
|
||||
Self {
|
||||
inner,
|
||||
extra_keys: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Record a new event with a provided timestamp.
|
||||
///
|
||||
/// It's the caller's responsibility to ensure the timestamp comes from the same clock source.
|
||||
/// Use [`glean::get_timestamp_ms`](crate::get_timestamp_ms) to get a valid timestamp.
|
||||
pub fn record_with_time(&self, timestamp: u64, extra: HashMap<String, String>) {
|
||||
self.inner.record_with_time(timestamp, extra);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::common_test::{lock_test, new_glean};
|
||||
use crate::CommonMetricData;
|
||||
|
||||
#[test]
|
||||
fn no_extra_keys() {
|
||||
let _lock = lock_test();
|
||||
let _t = new_glean(None, true);
|
||||
|
||||
let metric: EventMetric<NoExtraKeys> = EventMetric::new(CommonMetricData {
|
||||
name: "event".into(),
|
||||
category: "test".into(),
|
||||
send_in_pings: vec!["test1".into()],
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
metric.record(None);
|
||||
metric.record(None);
|
||||
|
||||
let data = metric.test_get_value(None).expect("no event recorded");
|
||||
assert_eq!(2, data.len());
|
||||
assert!(data[0].timestamp <= data[1].timestamp);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_extra_keys() {
|
||||
let _lock = lock_test();
|
||||
let _t = new_glean(None, true);
|
||||
|
||||
#[derive(Default, Debug, Clone, Hash, Eq, PartialEq)]
|
||||
struct SomeExtra {
|
||||
key1: Option<String>,
|
||||
key2: Option<String>,
|
||||
}
|
||||
|
||||
impl glean_core::traits::ExtraKeys for SomeExtra {
|
||||
const ALLOWED_KEYS: &'static [&'static str] = &["key1", "key2"];
|
||||
|
||||
fn into_ffi_extra(self) -> HashMap<String, String> {
|
||||
let mut map = HashMap::new();
|
||||
self.key1.and_then(|key1| map.insert("key1".into(), key1));
|
||||
self.key2.and_then(|key2| map.insert("key2".into(), key2));
|
||||
map
|
||||
}
|
||||
}
|
||||
|
||||
let metric: EventMetric<SomeExtra> = EventMetric::new(CommonMetricData {
|
||||
name: "event".into(),
|
||||
category: "test".into(),
|
||||
send_in_pings: vec!["test1".into()],
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let map1 = SomeExtra {
|
||||
key1: Some("1".into()),
|
||||
..Default::default()
|
||||
};
|
||||
metric.record(map1);
|
||||
|
||||
let map2 = SomeExtra {
|
||||
key1: Some("1".into()),
|
||||
key2: Some("2".into()),
|
||||
};
|
||||
metric.record(map2);
|
||||
|
||||
metric.record(None);
|
||||
|
||||
let data = metric.test_get_value(None).expect("no event recorded");
|
||||
assert_eq!(3, data.len());
|
||||
assert!(data[0].timestamp <= data[1].timestamp);
|
||||
assert!(data[1].timestamp <= data[2].timestamp);
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert("key1".into(), "1".into());
|
||||
assert_eq!(Some(map), data[0].extra);
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert("key1".into(), "1".into());
|
||||
map.insert("key2".into(), "2".into());
|
||||
assert_eq!(Some(map), data[1].extra);
|
||||
|
||||
assert_eq!(None, data[2].extra);
|
||||
}
|
||||
}
|
||||
|
||||
#[inherent(pub)]
|
||||
impl<K: traits::ExtraKeys> traits::Event for EventMetric<K> {
|
||||
type Extra = K;
|
||||
|
||||
fn record<M: Into<Option<<Self as traits::Event>::Extra>>>(&self, extra: M) {
|
||||
let extra = extra
|
||||
.into()
|
||||
.map(|e| e.into_ffi_extra())
|
||||
.unwrap_or_else(HashMap::new);
|
||||
self.inner.record(extra);
|
||||
}
|
||||
|
||||
fn test_get_value<'a, S: Into<Option<&'a str>>>(
|
||||
&self,
|
||||
ping_name: S,
|
||||
) -> Option<Vec<RecordedEvent>> {
|
||||
let ping_name = ping_name.into().map(|s| s.to_string());
|
||||
self.inner.test_get_value(ping_name)
|
||||
}
|
||||
|
||||
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
|
||||
&self,
|
||||
error: ErrorType,
|
||||
ping_name: S,
|
||||
) -> i32 {
|
||||
let ping_name = ping_name.into().map(|s| s.to_string());
|
||||
self.inner.test_get_num_recorded_errors(error, ping_name)
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
//! The different metric types supported by the Glean SDK to handle data.
|
||||
|
||||
mod event;
|
||||
mod ping;
|
||||
|
||||
pub use glean_core::BooleanMetric;
|
||||
|
@ -12,7 +13,7 @@ pub use glean_core::CustomDistributionMetric;
|
|||
pub use glean_core::UuidMetric;
|
||||
pub use glean_core::{Datetime, DatetimeMetric};
|
||||
//pub use glean_core::DenominatorMetric;
|
||||
pub use glean_core::EventMetric;
|
||||
pub use event::EventMetric;
|
||||
pub use glean_core::MemoryDistributionMetric;
|
||||
pub use glean_core::{AllowLabeled, LabeledMetric};
|
||||
//pub use glean_core::NumeratorMetric;
|
||||
|
|
|
@ -52,6 +52,19 @@ impl EventMetric {
|
|||
/// If any key is not allowed, an error is reported and no event is recorded.
|
||||
pub fn record(&self, extra: HashMap<String, String>) {
|
||||
let timestamp = time::precise_time_ns();
|
||||
self.record_with_time(timestamp, extra);
|
||||
}
|
||||
|
||||
/// Record a new event with a provided timestamp.
|
||||
///
|
||||
/// It's the caller's responsibility to ensure the timestamp comes from the same clock source.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `extra` - A [`HashMap`] of `(key, value)` pairs.
|
||||
/// Keys must be one of the allowed extra keys.
|
||||
/// If any key is not allowed, an error is reported and no event is recorded.
|
||||
pub fn record_with_time(&self, timestamp: u64, extra: HashMap<String, String>) {
|
||||
let metric = self.clone();
|
||||
crate::launch_with_glean(move |glean| metric.record_sync(glean, timestamp, extra));
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ pub trait ExtraKeys {
|
|||
/// 1. The list of extra key indices.
|
||||
/// Unset keys will be skipped.
|
||||
/// 2. The list of extra values.
|
||||
fn into_ffi_extra(self) -> HashMap<i32, String>;
|
||||
fn into_ffi_extra(self) -> HashMap<String, String>;
|
||||
}
|
||||
|
||||
/// Default of no extra keys for events.
|
||||
|
@ -44,7 +44,7 @@ pub enum NoExtraKeys {}
|
|||
impl ExtraKeys for NoExtraKeys {
|
||||
const ALLOWED_KEYS: &'static [&'static str] = &[];
|
||||
|
||||
fn into_ffi_extra(self) -> HashMap<i32, String> {
|
||||
fn into_ffi_extra(self) -> HashMap<String, String> {
|
||||
unimplemented!("non-existing extra keys can't be turned into a list")
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче