sui_indexer_alt_metrics/
db.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use prometheus::core::Collector;
5use prometheus::core::Desc;
6use prometheus::proto::Counter;
7use prometheus::proto::Gauge;
8use prometheus::proto::LabelPair;
9use prometheus::proto::Metric;
10use prometheus::proto::MetricFamily;
11use prometheus::proto::MetricType;
12use prometheus::proto::Summary;
13use sui_pg_db::Db;
14
15/// Collects information about the database connection pool.
16pub struct DbConnectionStatsCollector {
17    db: Db,
18    desc: Vec<(MetricType, Desc)>,
19}
20
21impl DbConnectionStatsCollector {
22    pub fn new(prefix: Option<&str>, db: Db) -> Self {
23        let prefix = prefix.unwrap_or("db");
24        let name = |n| format!("{prefix}_{n}");
25
26        let desc = vec![
27            (
28                MetricType::GAUGE,
29                desc(
30                    name("connections"),
31                    "Number of connections currently being managed by the pool",
32                ),
33            ),
34            (
35                MetricType::GAUGE,
36                desc(
37                    name("idle_connections"),
38                    "Number of idle connections in the pool",
39                ),
40            ),
41            (
42                MetricType::COUNTER,
43                desc(
44                    name("connect_direct"),
45                    "Connections that did not have to wait",
46                ),
47            ),
48            (
49                MetricType::SUMMARY,
50                desc(name("connect_waited"), "Connections that had to wait"),
51            ),
52            (
53                MetricType::COUNTER,
54                desc(
55                    name("connect_timed_out"),
56                    "Connections that timed out waiting for a connection",
57                ),
58            ),
59            (
60                MetricType::COUNTER,
61                desc(
62                    name("connections_created"),
63                    "Connections that have been created in the pool",
64                ),
65            ),
66            (
67                MetricType::COUNTER,
68                desc_with_labels(
69                    name("connections_closed"),
70                    "Total connections that were closed",
71                    &["reason"],
72                ),
73            ),
74        ];
75
76        Self { db, desc }
77    }
78}
79
80impl Collector for DbConnectionStatsCollector {
81    fn desc(&self) -> Vec<&Desc> {
82        self.desc.iter().map(|d| &d.1).collect()
83    }
84
85    fn collect(&self) -> Vec<MetricFamily> {
86        let state = self.db.state();
87        let stats = state.statistics;
88
89        vec![
90            gauge(&self.desc[0].1, state.connections as f64),
91            gauge(&self.desc[1].1, state.idle_connections as f64),
92            counter(&self.desc[2].1, stats.get_direct as f64),
93            summary(
94                &self.desc[3].1,
95                stats.get_wait_time.as_millis() as f64,
96                stats.get_waited + stats.get_timed_out,
97            ),
98            counter(&self.desc[4].1, stats.get_timed_out as f64),
99            counter(&self.desc[5].1, stats.connections_created as f64),
100            counter_with_labels(
101                &self.desc[6].1,
102                &[
103                    ("reason", "broken", stats.connections_closed_broken as f64),
104                    ("reason", "invalid", stats.connections_closed_invalid as f64),
105                    (
106                        "reason",
107                        "max_lifetime",
108                        stats.connections_closed_max_lifetime as f64,
109                    ),
110                    (
111                        "reason",
112                        "idle_timeout",
113                        stats.connections_closed_idle_timeout as f64,
114                    ),
115                ],
116            ),
117        ]
118    }
119}
120
121fn desc(name: String, help: &str) -> Desc {
122    desc_with_labels(name, help, &[])
123}
124
125fn desc_with_labels(name: String, help: &str, labels: &[&str]) -> Desc {
126    Desc::new(
127        name,
128        help.to_string(),
129        labels.iter().map(|s| s.to_string()).collect(),
130        Default::default(),
131    )
132    .expect("Bad metric description")
133}
134
135fn gauge(desc: &Desc, value: f64) -> MetricFamily {
136    let mut g = Gauge::default();
137    let mut m = Metric::default();
138    let mut mf = MetricFamily::new();
139
140    g.set_value(value);
141    m.set_gauge(g);
142
143    mf.mut_metric().push(m);
144    mf.set_name(desc.fq_name.clone());
145    mf.set_help(desc.help.clone());
146    mf.set_field_type(MetricType::GAUGE);
147    mf
148}
149
150fn counter(desc: &Desc, value: f64) -> MetricFamily {
151    let mut c = Counter::default();
152    let mut m = Metric::default();
153    let mut mf = MetricFamily::new();
154
155    c.set_value(value);
156    m.set_counter(c);
157
158    mf.mut_metric().push(m);
159    mf.set_name(desc.fq_name.clone());
160    mf.set_help(desc.help.clone());
161    mf.set_field_type(MetricType::COUNTER);
162    mf
163}
164
165fn counter_with_labels(desc: &Desc, values: &[(&str, &str, f64)]) -> MetricFamily {
166    let mut mf = MetricFamily::new();
167
168    for (name, label, value) in values {
169        let mut c = Counter::default();
170        let mut l = LabelPair::default();
171        let mut m = Metric::default();
172
173        c.set_value(*value);
174        l.set_name(name.to_string());
175        l.set_value(label.to_string());
176
177        m.set_counter(c);
178        m.mut_label().push(l);
179        mf.mut_metric().push(m);
180    }
181
182    mf.set_name(desc.fq_name.clone());
183    mf.set_help(desc.help.clone());
184    mf.set_field_type(MetricType::COUNTER);
185    mf
186}
187
188fn summary(desc: &Desc, sum: f64, count: u64) -> MetricFamily {
189    let mut s = Summary::default();
190    let mut m = Metric::default();
191    let mut mf = MetricFamily::new();
192
193    s.set_sample_sum(sum);
194    s.set_sample_count(count);
195    m.set_summary(s);
196
197    mf.mut_metric().push(m);
198    mf.set_name(desc.fq_name.clone());
199    mf.set_help(desc.help.clone());
200    mf.set_field_type(MetricType::SUMMARY);
201    mf
202}