use std::sync::atomic::AtomicUsize;
use serde::Serialize;
#[derive(Default, Debug, Serialize)]
#[non_exhaustive]
pub struct Metrics {
pub connection_count: AtomicUsize,
pub connections_in_pool: AtomicUsize,
pub active_wait_requests: AtomicUsize,
pub create_failed: AtomicUsize,
pub discarded_superfluous_connection: AtomicUsize,
pub discarded_unestablished_connection: AtomicUsize,
pub dirty_connection_return: AtomicUsize,
pub discarded_expired_connection: AtomicUsize,
pub resetting_connection: AtomicUsize,
pub discarded_error_during_cleanup: AtomicUsize,
pub connection_returned_to_pool: AtomicUsize,
#[cfg(feature = "hdrhistogram")]
pub connection_active_duration: MetricsHistogram,
#[cfg(feature = "hdrhistogram")]
pub connection_idle_duration: MetricsHistogram,
#[cfg(feature = "hdrhistogram")]
pub check_duration: MetricsHistogram,
#[cfg(feature = "hdrhistogram")]
pub connect_duration: MetricsHistogram,
}
impl Metrics {
#[cfg(feature = "hdrhistogram")]
pub fn clear_histograms(&self) {
self.connection_active_duration.reset();
self.connection_idle_duration.reset();
self.check_duration.reset();
self.connect_duration.reset();
}
}
#[cfg(feature = "hdrhistogram")]
#[derive(Debug)]
pub struct MetricsHistogram(std::sync::Mutex<hdrhistogram::Histogram<u64>>);
#[cfg(feature = "hdrhistogram")]
impl MetricsHistogram {
pub fn reset(&self) {
self.lock().unwrap().reset();
}
}
#[cfg(feature = "hdrhistogram")]
impl Default for MetricsHistogram {
fn default() -> Self {
let hdr = hdrhistogram::Histogram::new_with_bounds(1, 30 * 1_000_000, 2).unwrap();
Self(std::sync::Mutex::new(hdr))
}
}
#[cfg(feature = "hdrhistogram")]
impl Serialize for MetricsHistogram {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let hdr = self.0.lock().unwrap();
macro_rules! ile {
($e:expr) => {
&MetricAlias(concat!("!|quantile=", $e), hdr.value_at_quantile($e))
};
}
macro_rules! qual {
($e:expr) => {
&MetricAlias("<|", $e)
};
}
use serde::ser::SerializeMap;
let mut tup = serializer.serialize_map(Some(10))?;
tup.serialize_entry("samples", qual!(hdr.len()))?;
tup.serialize_entry("min", qual!(hdr.min()))?;
tup.serialize_entry("max", qual!(hdr.max()))?;
tup.serialize_entry("mean", qual!(hdr.mean()))?;
tup.serialize_entry("stdev", qual!(hdr.stdev()))?;
tup.serialize_entry("90%ile", ile!(0.9))?;
tup.serialize_entry("95%ile", ile!(0.95))?;
tup.serialize_entry("99%ile", ile!(0.99))?;
tup.serialize_entry("99.9%ile", ile!(0.999))?;
tup.serialize_entry("99.99%ile", ile!(0.9999))?;
tup.end()
}
}
#[cfg(feature = "hdrhistogram")]
struct MetricAlias<T: Serialize>(&'static str, T);
#[cfg(feature = "hdrhistogram")]
impl<T: Serialize> Serialize for MetricAlias<T> {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_newtype_struct(self.0, &self.1)
}
}
#[cfg(feature = "hdrhistogram")]
impl std::ops::Deref for MetricsHistogram {
type Target = std::sync::Mutex<hdrhistogram::Histogram<u64>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}