1use std::sync::atomic::AtomicUsize;
23use serde::Serialize;
45#[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.
10pub connection_count: AtomicUsize,
11/// Guage of active connections that currently belong to the pool.
12pub connections_in_pool: AtomicUsize,
13/// Guage of GetConn requests that are currently active.
14pub active_wait_requests: AtomicUsize,
15/// Counter of connections that failed to be created.
16pub create_failed: AtomicUsize,
17/// Counter of connections discarded due to pool constraints.
18pub discarded_superfluous_connection: AtomicUsize,
19/// Counter of connections discarded due to being closed upon return to the pool.
20pub 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).
23pub dirty_connection_return: AtomicUsize,
24/// Counter of connections that have been discarded as they were expired by the pool constraints.
25pub discarded_expired_connection: AtomicUsize,
26/// Counter of connections that have been reset.
27pub resetting_connection: AtomicUsize,
28/// Counter of connections that have been discarded as they returned an error during cleanup.
29pub discarded_error_during_cleanup: AtomicUsize,
30/// Counter of connections that have been returned to the pool.
31pub connection_returned_to_pool: AtomicUsize,
32/// Histogram of times connections have spent outside of the pool.
33#[cfg(feature = "hdrhistogram")]
34pub connection_active_duration: MetricsHistogram,
35/// Histogram of times connections have spent inside of the pool.
36#[cfg(feature = "hdrhistogram")]
37pub connection_idle_duration: MetricsHistogram,
38/// Histogram of times connections have spent being checked for health.
39#[cfg(feature = "hdrhistogram")]
40pub check_duration: MetricsHistogram,
41/// Histogram of time spent waiting to connect to the server.
42#[cfg(feature = "hdrhistogram")]
43pub connect_duration: MetricsHistogram,
44}
4546impl 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")]
49pub fn clear_histograms(&self) {
50self.connection_active_duration.reset();
51self.connection_idle_duration.reset();
52self.check_duration.reset();
53self.connect_duration.reset();
54 }
55}
5657#[cfg(feature = "hdrhistogram")]
58#[derive(Debug)]
59pub struct MetricsHistogram(std::sync::Mutex<hdrhistogram::Histogram<u64>>);
6061#[cfg(feature = "hdrhistogram")]
62impl MetricsHistogram {
63pub fn reset(&self) {
64self.lock().unwrap().reset();
65 }
66}
6768#[cfg(feature = "hdrhistogram")]
69impl Default for MetricsHistogram {
70fn default() -> Self {
71let hdr = hdrhistogram::Histogram::new_with_bounds(1, 30 * 1_000_000, 2).unwrap();
72Self(std::sync::Mutex::new(hdr))
73 }
74}
7576#[cfg(feature = "hdrhistogram")]
77impl Serialize for MetricsHistogram {
78fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
79where
80S: serde::Serializer,
81 {
82let hdr = self.0.lock().unwrap();
8384/// 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`).
87macro_rules! ile {
88 ($e:expr) => {
89&MetricAlias(concat!("!|quantile=", $e), hdr.value_at_quantile($e))
90 };
91 }
9293/// 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`.
97macro_rules! qual {
98 ($e:expr) => {
99&MetricAlias("<|", $e)
100 };
101 }
102103use serde::ser::SerializeMap;
104105let 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}
119120/// 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);
127128#[cfg(feature = "hdrhistogram")]
129impl<T: Serialize> Serialize for MetricAlias<T> {
130fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
131where
132S: serde::Serializer,
133 {
134 serializer.serialize_newtype_struct(self.0, &self.1)
135 }
136}
137138#[cfg(feature = "hdrhistogram")]
139impl std::ops::Deref for MetricsHistogram {
140type Target = std::sync::Mutex<hdrhistogram::Histogram<u64>>;
141142fn deref(&self) -> &Self::Target {
143&self.0
144}
145}