use prometheus::{
exponential_buckets, histogram_opts, linear_buckets, register_histogram_vec,
register_int_counter_vec, HistogramVec, IntCounterVec, Opts,
};
use crate::time::Instant;
const LINERA_NAMESPACE: &str = "linera";
pub fn register_int_counter_vec(
name: &str,
description: &str,
label_names: &[&str],
) -> IntCounterVec {
let counter_opts = Opts::new(name, description).namespace(LINERA_NAMESPACE);
register_int_counter_vec!(counter_opts, label_names).expect("IntCounter can be created")
}
pub fn register_histogram_vec(
name: &str,
description: &str,
label_names: &[&str],
buckets: Option<Vec<f64>>,
) -> HistogramVec {
let histogram_opts = if let Some(buckets) = buckets {
histogram_opts!(name, description, buckets).namespace(LINERA_NAMESPACE)
} else {
histogram_opts!(name, description).namespace(LINERA_NAMESPACE)
};
register_histogram_vec!(histogram_opts, label_names).expect("Histogram can be created")
}
pub fn exponential_bucket_interval(start_value: f64, end_value: f64) -> Option<Vec<f64>> {
let quot = end_value / start_value;
let factor = 3.0_f64;
let count_approx = quot.ln() / factor.ln();
let count = count_approx.round() as usize;
let mut buckets = exponential_buckets(start_value, factor, count)
.expect("Exponential buckets creation should not fail!");
if let Some(last) = buckets.last() {
if *last < end_value {
buckets.push(end_value);
}
}
Some(buckets)
}
pub fn exponential_bucket_latencies(max_latency: f64) -> Option<Vec<f64>> {
exponential_bucket_interval(0.001_f64, max_latency)
}
pub fn linear_bucket_interval(start_value: f64, width: f64, end_value: f64) -> Option<Vec<f64>> {
let count = (end_value - start_value) / width;
let count = count.ceil() as usize;
Some(
linear_buckets(start_value, width, count)
.expect("Linear buckets creation should not fail!"),
)
}
pub fn linear_bucket_latencies(max_latency: f64) -> Option<Vec<f64>> {
linear_bucket_interval(1.0, 50.0, max_latency)
}
pub struct ActiveMeasurementGuard<'metric, Metric>
where
Metric: MeasureLatency,
{
start: Instant,
metric: Option<&'metric Metric>,
}
impl<Metric> ActiveMeasurementGuard<'_, Metric>
where
Metric: MeasureLatency,
{
pub fn finish(mut self) -> f64 {
self.finish_by_ref()
}
fn finish_by_ref(&mut self) -> f64 {
match self.metric.take() {
Some(metric) => {
let latency = self.start.elapsed().as_secs_f64() * 1000.0;
metric.finish_measurement(latency);
latency
}
None => {
f64::NAN
}
}
}
}
impl<Metric> Drop for ActiveMeasurementGuard<'_, Metric>
where
Metric: MeasureLatency,
{
fn drop(&mut self) {
self.finish_by_ref();
}
}
pub trait MeasureLatency: Sized {
fn measure_latency(&self) -> ActiveMeasurementGuard<'_, Self>;
fn finish_measurement(&self, milliseconds: f64);
}
impl MeasureLatency for HistogramVec {
fn measure_latency(&self) -> ActiveMeasurementGuard<'_, Self> {
ActiveMeasurementGuard {
start: Instant::now(),
metric: Some(self),
}
}
fn finish_measurement(&self, milliseconds: f64) {
self.with_label_values(&[]).observe(milliseconds);
}
}