use crate::Clock;
use prometheus_client::metrics::histogram::Histogram;
use std::{sync::Arc, time::SystemTime};
pub struct Buckets;
impl Buckets {
pub const NETWORK: [f64; 13] = [
0.010, 0.020, 0.050, 0.100, 0.200, 0.500, 1.0, 2.0, 5.0, 10.0, 30.0, 60.0, 300.0,
];
pub const LOCAL: [f64; 12] = [
3e-6, 1e-5, 3e-5, 1e-4, 3e-4, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1.0,
];
pub const CRYPTOGRAPHY: [f64; 16] = [
3e-6, 1e-5, 3e-5, 1e-4, 3e-4, 0.001, 0.002, 0.003, 0.005, 0.01, 0.015, 0.02, 0.025, 0.03,
0.1, 0.2,
];
}
pub trait HistogramExt {
fn observe_between(&self, start: SystemTime, end: SystemTime);
}
impl HistogramExt for Histogram {
fn observe_between(&self, start: SystemTime, end: SystemTime) {
let duration = end.duration_since(start).map_or(
0.0,
|duration| duration.as_secs_f64(),
);
self.observe(duration);
}
}
#[derive(Clone)]
pub struct Timed<C: Clock> {
histogram: Histogram,
clock: Arc<C>,
}
impl<C: Clock> Timed<C> {
pub const fn new(histogram: Histogram, clock: Arc<C>) -> Self {
Self { histogram, clock }
}
pub fn timer(&self) -> Timer<C> {
let start = self.clock.current();
Timer {
histogram: self.histogram.clone(),
clock: self.clock.clone(), start,
canceled: false,
}
}
pub fn time_some<T, F: FnOnce() -> Option<T>>(&self, f: F) -> Option<T> {
let start = self.clock.current();
let result = f();
if result.is_some() {
self.histogram.observe_between(start, self.clock.current());
}
result
}
}
pub struct Timer<C: Clock> {
histogram: Histogram,
clock: Arc<C>,
start: SystemTime,
canceled: bool,
}
impl<C: Clock> Timer<C> {
pub fn observe(&mut self) {
self.canceled = true;
let end = self.clock.current();
self.histogram.observe_between(self.start, end);
}
pub fn cancel(mut self) {
self.canceled = true;
}
}
impl<C: Clock> Drop for Timer<C> {
fn drop(&mut self) {
if self.canceled {
return;
}
self.observe();
}
}