Skip to main content

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