sui_indexer_alt_metrics/
db.rs

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