зеркало из https://github.com/mozilla/glean.git
Add a Datetime metric type in the RLB
This commit is contained in:
Родитель
29cd9970a4
Коммит
895fa243e5
|
@ -436,6 +436,7 @@ dependencies = [
|
|||
name = "glean"
|
||||
version = "33.8.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossbeam-channel 0.4.4",
|
||||
"env_logger",
|
||||
"flate2",
|
||||
|
|
|
@ -33,6 +33,7 @@ thiserror = "1.0.4"
|
|||
serde_json = "1.0.44"
|
||||
serde = { version = "1.0.104", features = ["derive"] }
|
||||
uuid = { version = "0.8.1", features = ["v4"] }
|
||||
chrono = { version = "0.4.10", features = ["serde"] }
|
||||
time = "0.1.40"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
// 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::sync::Arc;
|
||||
|
||||
use glean_core::metrics::MetricType;
|
||||
pub use glean_core::metrics::{Datetime, TimeUnit};
|
||||
use glean_core::ErrorType;
|
||||
|
||||
use crate::dispatcher;
|
||||
|
||||
// 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.
|
||||
|
||||
/// This implements the developer facing API for recording Datetime 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 DatetimeMetric(pub(crate) Arc<glean_core::metrics::DatetimeMetric>);
|
||||
|
||||
impl DatetimeMetric {
|
||||
/// The public constructor used by automatically generated metrics.
|
||||
pub fn new(meta: glean_core::CommonMetricData, time_unit: TimeUnit) -> Self {
|
||||
Self(Arc::new(glean_core::metrics::DatetimeMetric::new(
|
||||
meta, time_unit,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
#[inherent(pub)]
|
||||
impl glean_core::traits::Datetime for DatetimeMetric {
|
||||
fn set(&self, value: Option<Datetime>) {
|
||||
let metric = Arc::clone(&self.0);
|
||||
dispatcher::launch(move || crate::with_glean(|glean| metric.set(glean, value)));
|
||||
}
|
||||
|
||||
fn test_get_value<'a, S: Into<Option<&'a str>>>(&self, ping_name: S) -> Option<Datetime> {
|
||||
dispatcher::block_on_queue();
|
||||
|
||||
let queried_ping_name = ping_name
|
||||
.into()
|
||||
.unwrap_or_else(|| &self.0.meta().send_in_pings[0]);
|
||||
|
||||
crate::with_glean(|glean| self.0.test_get_value(glean, queried_ping_name))
|
||||
}
|
||||
|
||||
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
|
||||
&self,
|
||||
error: ErrorType,
|
||||
ping_name: S,
|
||||
) -> i32 {
|
||||
dispatcher::block_on_queue();
|
||||
|
||||
crate::with_glean_mut(|glean| {
|
||||
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())
|
||||
.unwrap_or(0)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::common_test::{lock_test, new_glean};
|
||||
use crate::CommonMetricData;
|
||||
use chrono::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn datetime_convenient_api() {
|
||||
let _lock = lock_test();
|
||||
let _t = new_glean(None, true);
|
||||
|
||||
let metric: DatetimeMetric = DatetimeMetric::new(
|
||||
CommonMetricData {
|
||||
name: "datetime".into(),
|
||||
category: "test".into(),
|
||||
send_in_pings: vec!["test1".into()],
|
||||
..Default::default()
|
||||
},
|
||||
TimeUnit::Day,
|
||||
);
|
||||
|
||||
// Record a date: it will get truncated to Day resolution.
|
||||
let sample_date = FixedOffset::east(0).ymd(2018, 2, 25).and_hms(11, 5, 0);
|
||||
metric.set(Some(sample_date));
|
||||
|
||||
// Check that the value has the correct resolution.
|
||||
let date = metric.test_get_value(None).unwrap();
|
||||
assert_eq!(date, FixedOffset::east(0).ymd(2018, 2, 25).and_hms(0, 0, 0));
|
||||
|
||||
// Ensure no error was recorded.
|
||||
assert_eq!(
|
||||
metric.test_get_num_recorded_errors(ErrorType::InvalidValue, None),
|
||||
0
|
||||
)
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
mod boolean;
|
||||
mod counter;
|
||||
mod datetime;
|
||||
mod event;
|
||||
mod labeled;
|
||||
mod memory_distribution;
|
||||
|
@ -20,6 +21,7 @@ mod uuid;
|
|||
pub use self::uuid::UuidMetric;
|
||||
pub use boolean::BooleanMetric;
|
||||
pub use counter::CounterMetric;
|
||||
pub use datetime::{Datetime, DatetimeMetric};
|
||||
pub use event::EventMetric;
|
||||
pub use labeled::{AllowLabeled, LabeledMetric};
|
||||
pub use memory_distribution::MemoryDistributionMetric;
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::util::{get_iso_time_string, local_now_with_offset};
|
|||
use crate::CommonMetricData;
|
||||
use crate::Glean;
|
||||
|
||||
use chrono::{DateTime, FixedOffset, TimeZone};
|
||||
use chrono::{DateTime, FixedOffset, TimeZone, Timelike};
|
||||
|
||||
/// A datetime type.
|
||||
///
|
||||
|
@ -143,6 +143,64 @@ impl DatetimeMetric {
|
|||
}
|
||||
}
|
||||
|
||||
/// **Test-only API (exported for FFI purposes).**
|
||||
///
|
||||
/// Gets the stored datetime value.
|
||||
///
|
||||
/// The precision of this value is truncated to the `time_unit` precision.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `glean` - the Glean instance this metric belongs to.
|
||||
/// * `storage_name` - the storage name to look into.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// The stored value or `None` if nothing stored.
|
||||
pub fn test_get_value(&self, glean: &Glean, storage_name: &str) -> Option<Datetime> {
|
||||
match StorageManager.snapshot_metric(
|
||||
glean.storage(),
|
||||
storage_name,
|
||||
&self.meta.identifier(glean),
|
||||
) {
|
||||
Some(Metric::Datetime(d, tu)) => {
|
||||
// The string version of the test function truncates using string
|
||||
// parsing. Unfortunately `parse_from_str` errors with `NotEnough` if we
|
||||
// try to truncate with `get_iso_time_string` and then parse it back
|
||||
// in a `Datetime`. So we need to truncate manually.
|
||||
let time = d.time();
|
||||
match tu {
|
||||
TimeUnit::Nanosecond => d.date().and_hms_nano_opt(
|
||||
time.hour(),
|
||||
time.minute(),
|
||||
time.second(),
|
||||
time.nanosecond(),
|
||||
),
|
||||
TimeUnit::Microsecond => d.date().and_hms_nano_opt(
|
||||
time.hour(),
|
||||
time.minute(),
|
||||
time.second(),
|
||||
time.nanosecond() / 1000,
|
||||
),
|
||||
TimeUnit::Millisecond => d.date().and_hms_nano_opt(
|
||||
time.hour(),
|
||||
time.minute(),
|
||||
time.second(),
|
||||
time.nanosecond() / 1000000,
|
||||
),
|
||||
TimeUnit::Second => {
|
||||
d.date()
|
||||
.and_hms_nano_opt(time.hour(), time.minute(), time.second(), 0)
|
||||
}
|
||||
TimeUnit::Minute => d.date().and_hms_nano_opt(time.hour(), time.minute(), 0, 0),
|
||||
TimeUnit::Hour => d.date().and_hms_nano_opt(time.hour(), 0, 0, 0),
|
||||
TimeUnit::Day => d.date().and_hms_nano_opt(0, 0, 0, 0),
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// **Test-only API (exported for FFI purposes).**
|
||||
///
|
||||
/// Gets the currently stored value as a String.
|
||||
|
|
Загрузка…
Ссылка в новой задаче