use crate::common_metric_data::CommonMetricDataInternal;
use crate::error_recording::{record_error, test_get_num_recorded_errors, ErrorType};
use crate::metrics::Metric;
use crate::metrics::MetricType;
use crate::storage::StorageManager;
use crate::Glean;
use crate::{CommonMetricData, TestGetValue};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Rate {
pub numerator: i32,
pub denominator: i32,
}
impl From<(i32, i32)> for Rate {
fn from((num, den): (i32, i32)) -> Self {
Self {
numerator: num,
denominator: den,
}
}
}
#[derive(Clone, Debug)]
pub struct RateMetric {
meta: CommonMetricDataInternal,
}
impl MetricType for RateMetric {
fn meta(&self) -> &CommonMetricDataInternal {
&self.meta
}
}
impl RateMetric {
pub fn new(meta: CommonMetricData) -> Self {
Self { meta: meta.into() }
}
pub fn add_to_numerator(&self, amount: i32) {
let metric = self.clone();
crate::launch_with_glean(move |glean| metric.add_to_numerator_sync(glean, amount))
}
#[doc(hidden)]
pub fn add_to_numerator_sync(&self, glean: &Glean, amount: i32) {
if !self.should_record(glean) {
return;
}
if amount < 0 {
record_error(
glean,
&self.meta,
ErrorType::InvalidValue,
format!("Added negative value {} to numerator", amount),
None,
);
return;
}
glean
.storage()
.record_with(glean, &self.meta, |old_value| match old_value {
Some(Metric::Rate(num, den)) => Metric::Rate(num.saturating_add(amount), den),
_ => Metric::Rate(amount, 0), });
}
pub fn add_to_denominator(&self, amount: i32) {
let metric = self.clone();
crate::launch_with_glean(move |glean| metric.add_to_denominator_sync(glean, amount))
}
#[doc(hidden)]
pub fn add_to_denominator_sync(&self, glean: &Glean, amount: i32) {
if !self.should_record(glean) {
return;
}
if amount < 0 {
record_error(
glean,
&self.meta,
ErrorType::InvalidValue,
format!("Added negative value {} to denominator", amount),
None,
);
return;
}
glean
.storage()
.record_with(glean, &self.meta, |old_value| match old_value {
Some(Metric::Rate(num, den)) => Metric::Rate(num, den.saturating_add(amount)),
_ => Metric::Rate(0, amount),
});
}
#[doc(hidden)]
pub fn get_value<'a, S: Into<Option<&'a str>>>(
&self,
glean: &Glean,
ping_name: S,
) -> Option<Rate> {
let queried_ping_name = ping_name
.into()
.unwrap_or_else(|| &self.meta().inner.send_in_pings[0]);
match StorageManager.snapshot_metric(
glean.storage(),
queried_ping_name,
&self.meta.identifier(glean),
self.meta.inner.lifetime,
) {
Some(Metric::Rate(n, d)) => Some((n, d).into()),
_ => None,
}
}
pub fn test_get_num_recorded_errors(&self, error: ErrorType) -> i32 {
crate::block_on_dispatcher();
crate::core::with_glean(|glean| {
test_get_num_recorded_errors(glean, self.meta(), error).unwrap_or(0)
})
}
}
impl TestGetValue for RateMetric {
type Output = Rate;
fn test_get_value(&self, ping_name: Option<String>) -> Option<Rate> {
crate::block_on_dispatcher();
crate::core::with_glean(|glean| self.get_value(glean, ping_name.as_deref()))
}
}