1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
//! A module defining the [`Metric`] trait and common metric backends.
use crate::clear::{Clear, Clearable};
/// Re-export `aspect-rs`'s types to avoid crates depending on it.
pub use aspect::{Advice, Enter, OnResult, OnResultMut};
use serde::Serialize;
use std::marker::PhantomData;
/// A trait to implement to be used in the `measure!` macro
///
/// Metrics wrap expressions to measure them.
///
/// The return type, R, of the expression can be captured to perform special
/// handling.
pub trait Metric<R>: Default + OnResultMut<R> + Clear + Serialize {}
// Needed to force `measure!` to work only with the [`Metric`] trait.
#[doc(hidden)]
pub fn on_result<R, A: Metric<R>>(metric: &A, _enter: <A as Enter>::E, _result: &mut R) -> Advice {
metric.on_result(_enter, _result)
}
/// Handles a metric's lifecycle, guarding against early returns and panics.
pub struct ExitGuard<'a, R, M: Metric<R>> {
metric: &'a M,
enter: Option<<M as Enter>::E>,
_phantom: PhantomData<R>,
}
impl<'a, R, M: Metric<R>> ExitGuard<'a, R, M> {
/// Enter a metric and create the guard for its exit.
/// This calls [`aspect::Enter::enter`] on the metric internally.
pub fn new(metric: &'a M) -> Self {
Self {
metric,
enter: Some(metric.enter()),
_phantom: PhantomData,
}
}
/// If no unexpected exit occurred, record the expression's result.
pub fn on_result(mut self, result: &mut R) {
if let Some(enter) = self.enter.take() {
self.metric.on_result(enter, result);
} else {
// OnResult called twice - we ignore
}
}
}
impl<'a, R, M: Metric<R>> Drop for ExitGuard<'a, R, M> {
fn drop(&mut self) {
if let Some(enter) = self.enter.take() {
self.metric.leave_scope(enter);
} else {
// on_result was called, so the result was already recorded
}
}
}
/// A trait for Counters
pub trait Counter: Default + Clear + Clearable + Serialize {
/// Increment the counter
fn incr(&self) {
self.incr_by(1)
}
/// Increment the counter by count in one step
///
/// Supplying a count larger than the underlying counter's remaining
/// capacity will wrap like [`u8::wrapping_add`] and similar methods.
fn incr_by(&self, count: usize);
}
/// A trait for Gauges
pub trait Gauge: Default + Clear + Serialize {
/// Increment the counter
fn incr(&self) {
self.incr_by(1)
}
/// Decrement the counter
fn decr(&self) {
self.decr_by(1)
}
/// Increment the gauge by count in one step
///
/// Supplying a count larger than the underlying counter's remaining
/// capacity will wrap like [`u8::wrapping_add`] and similar methods.
fn incr_by(&self, count: usize);
/// Decrement the gauge by count in one step
///
/// Supplying a count larger than the underlying counter's current value
/// will wrap like [`u8::wrapping_sub`] and similar methods.
fn decr_by(&self, count: usize);
}
/// A trait for Histograms
pub trait Histogram: Clear + Serialize {
/// Build a new histogram with the given max bounds
fn with_bound(max_value: u64) -> Self;
/// Record a value to the histogram.
///
/// It will saturate if the value is higher than the histogram's
/// `max_value`.
fn record(&self, value: u64);
}