mysql_async/conn/pool/
metrics.rs

1use std::sync::atomic::AtomicUsize;
2
3use serde::Serialize;
4
5#[derive(Default, Debug, Serialize)]
6#[non_exhaustive]
7pub struct Metrics {
8    /// Guage of active connections to the database server, this includes both connections that have belong
9    /// to the pool, and connections currently owned by the application.
10    pub connection_count: AtomicUsize,
11    /// Guage of active connections that currently belong to the pool.
12    pub connections_in_pool: AtomicUsize,
13    /// Guage of GetConn requests that are currently active.
14    pub active_wait_requests: AtomicUsize,
15    /// Counter of connections that failed to be created.
16    pub create_failed: AtomicUsize,
17    /// Counter of connections discarded due to pool constraints.
18    pub discarded_superfluous_connection: AtomicUsize,
19    /// Counter of connections discarded due to being closed upon return to the pool.
20    pub discarded_unestablished_connection: AtomicUsize,
21    /// Counter of connections that have been returned to the pool dirty that needed to be cleaned
22    /// (ie. open transactions, pending queries, etc).
23    pub dirty_connection_return: AtomicUsize,
24    /// Counter of connections that have been discarded as they were expired by the pool constraints.
25    pub discarded_expired_connection: AtomicUsize,
26    /// Counter of connections that have been reset.
27    pub resetting_connection: AtomicUsize,
28    /// Counter of connections that have been discarded as they returned an error during cleanup.
29    pub discarded_error_during_cleanup: AtomicUsize,
30    /// Counter of connections that have been returned to the pool.
31    pub connection_returned_to_pool: AtomicUsize,
32    /// Histogram of times connections have spent outside of the pool.
33    #[cfg(feature = "hdrhistogram")]
34    pub connection_active_duration: MetricsHistogram,
35    /// Histogram of times connections have spent inside of the pool.
36    #[cfg(feature = "hdrhistogram")]
37    pub connection_idle_duration: MetricsHistogram,
38    /// Histogram of times connections have spent being checked for health.
39    #[cfg(feature = "hdrhistogram")]
40    pub check_duration: MetricsHistogram,
41    /// Histogram of time spent waiting to connect to the server.
42    #[cfg(feature = "hdrhistogram")]
43    pub connect_duration: MetricsHistogram,
44}
45
46impl Metrics {
47    /// Resets all histograms to allow for histograms to be bound to a period of time (ie. between metric scrapes)
48    #[cfg(feature = "hdrhistogram")]
49    pub fn clear_histograms(&self) {
50        self.connection_active_duration.reset();
51        self.connection_idle_duration.reset();
52        self.check_duration.reset();
53        self.connect_duration.reset();
54    }
55}
56
57#[cfg(feature = "hdrhistogram")]
58#[derive(Debug)]
59pub struct MetricsHistogram(std::sync::Mutex<hdrhistogram::Histogram<u64>>);
60
61#[cfg(feature = "hdrhistogram")]
62impl MetricsHistogram {
63    pub fn reset(&self) {
64        self.lock().unwrap().reset();
65    }
66}
67
68#[cfg(feature = "hdrhistogram")]
69impl Default for MetricsHistogram {
70    fn default() -> Self {
71        let hdr = hdrhistogram::Histogram::new_with_bounds(1, 30 * 1_000_000, 2).unwrap();
72        Self(std::sync::Mutex::new(hdr))
73    }
74}
75
76#[cfg(feature = "hdrhistogram")]
77impl Serialize for MetricsHistogram {
78    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
79    where
80        S: serde::Serializer,
81    {
82        let hdr = self.0.lock().unwrap();
83
84        /// A percentile of this histogram - for supporting serializers this
85        /// will ignore the key (such as `90%ile`) and instead add a
86        /// dimension to the metrics (such as `quantile=0.9`).
87        macro_rules! ile {
88            ($e:expr) => {
89                &MetricAlias(concat!("!|quantile=", $e), hdr.value_at_quantile($e))
90            };
91        }
92
93        /// A 'qualified' metric name - for supporting serializers such as
94        /// serde_prometheus, this will prepend the metric name to this key,
95        /// outputting `response_time_count`, for example rather than just
96        /// `count`.
97        macro_rules! qual {
98            ($e:expr) => {
99                &MetricAlias("<|", $e)
100            };
101        }
102
103        use serde::ser::SerializeMap;
104
105        let mut tup = serializer.serialize_map(Some(10))?;
106        tup.serialize_entry("samples", qual!(hdr.len()))?;
107        tup.serialize_entry("min", qual!(hdr.min()))?;
108        tup.serialize_entry("max", qual!(hdr.max()))?;
109        tup.serialize_entry("mean", qual!(hdr.mean()))?;
110        tup.serialize_entry("stdev", qual!(hdr.stdev()))?;
111        tup.serialize_entry("90%ile", ile!(0.9))?;
112        tup.serialize_entry("95%ile", ile!(0.95))?;
113        tup.serialize_entry("99%ile", ile!(0.99))?;
114        tup.serialize_entry("99.9%ile", ile!(0.999))?;
115        tup.serialize_entry("99.99%ile", ile!(0.9999))?;
116        tup.end()
117    }
118}
119
120/// This is a mocked 'newtype' (eg. `A(u64)`) that instead allows us to
121/// define our own type name that doesn't have to abide by Rust's constraints
122/// on type names. This allows us to do some manipulation of our metrics,
123/// allowing us to add dimensionality to our metrics via key=value pairs, or
124/// key manipulation on serializers that support it.
125#[cfg(feature = "hdrhistogram")]
126struct MetricAlias<T: Serialize>(&'static str, T);
127
128#[cfg(feature = "hdrhistogram")]
129impl<T: Serialize> Serialize for MetricAlias<T> {
130    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
131    where
132        S: serde::Serializer,
133    {
134        serializer.serialize_newtype_struct(self.0, &self.1)
135    }
136}
137
138#[cfg(feature = "hdrhistogram")]
139impl std::ops::Deref for MetricsHistogram {
140    type Target = std::sync::Mutex<hdrhistogram::Histogram<u64>>;
141
142    fn deref(&self) -> &Self::Target {
143        &self.0
144    }
145}