mithril_aggregator/metrics/
service.rs

1use std::collections::HashMap;
2
3use mithril_metric::{MetricCounterWithLabels, MetricsServiceExporter, build_metrics_service};
4
5use mithril_metric::metric::{MetricCollector, MetricCounter};
6use prometheus::proto::{LabelPair, Metric, MetricFamily};
7
8// Those are three differents dimensions, they use the same value to simplify usage in Grafana
9static CLIENT_ORIGIN_TAG_LABEL: &str = "origin_tag";
10static SIGNER_REGISTRATION_ORIGIN_TAG_LABEL: &str = "origin_tag";
11static SIGNER_SIGNATURE_ORIGIN_TAG_LABEL: &str = "origin_tag";
12static CLIENT_TYPE_LABEL: &str = "client_type";
13
14build_metrics_service!(
15    MetricsService,
16
17    certificate_detail_total_served_since_startup:MetricCounterWithLabels(
18        "certificate_detail_total_served_since_startup",
19        "Number of certificate details served since startup on a Mithril aggregator node",
20        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
21    ),
22    artifact_detail_cardano_immutable_files_full_total_served_since_startup:MetricCounterWithLabels(
23        "mithril_aggregator_artifact_detail_cardano_db_total_served_since_startup",
24        "Number of Cardano immutable files full artifact details served since startup on a Mithril aggregator node",
25        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
26    ),
27    cardano_immutable_files_full_total_restoration_since_startup:MetricCounterWithLabels(
28        "mithril_aggregator_cardano_db_total_restoration_since_startup",
29        "Number of Cardano immutable files full restorations since startup on a Mithril aggregator node",
30        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
31    ),
32    cardano_database_immutable_files_restored_since_startup:MetricCounterWithLabels(
33        "mithril_aggregator_cardano_db_immutable_files_restored_since_startup",
34        "Number of Cardano immutable files restored since startup on a Mithril aggregator node",
35        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
36    ),
37    cardano_database_ancillary_files_restored_since_startup:MetricCounterWithLabels(
38        "mithril_aggregator_cardano_db_ancillary_files_restored_since_startup",
39        "Number of Cardano ancillary files restored since startup on a Mithril aggregator node",
40        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
41    ),
42    cardano_database_complete_restoration_since_startup:MetricCounterWithLabels(
43        "mithril_aggregator_cardano_db_complete_restoration_since_startup",
44        "Number of complete Cardano database restoration since startup on a Mithril aggregator node",
45        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
46    ),
47    cardano_database_partial_restoration_since_startup:MetricCounterWithLabels(
48        "mithril_aggregator_cardano_db_partial_restoration_since_startup",
49        "Number of partial Cardano database restoration since startup on a Mithril aggregator node",
50        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
51    ),
52    artifact_detail_cardano_database_total_served_since_startup:MetricCounterWithLabels(
53        "mithril_aggregator_artifact_detail_cardano_database_total_served_since_startup",
54        "Number of Cardano database artifact details served since startup on a Mithril aggregator node",
55        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
56    ),
57    artifact_detail_mithril_stake_distribution_total_served_since_startup:MetricCounterWithLabels(
58        "mithril_aggregator_artifact_detail_mithril_stake_distribution_total_served_since_startup",
59        "Number of Mithril stake distribution artifact details served since startup on a Mithril aggregator node",
60        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
61    ),
62    artifact_detail_cardano_stake_distribution_total_served_since_startup:MetricCounterWithLabels(
63        "mithril_aggregator_artifact_detail_cardano_stake_distribution_total_served_since_startup",
64        "Number of Cardano stake distribution artifact details served since startup on a Mithril aggregator node",
65        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
66    ),
67    artifact_detail_cardano_transaction_total_served_since_startup:MetricCounterWithLabels(
68        "mithril_aggregator_artifact_detail_cardano_transaction_total_served_since_startup",
69        "Number of Cardano transaction artifact details served since startup on a Mithril aggregator node",
70        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
71    ),
72    artifact_detail_cardano_blocks_transactions_total_served_since_startup:MetricCounterWithLabels(
73        "mithril_aggregator_artifact_detail_cardano_blocks_transactions_total_served_since_startup",
74        "Number of Cardano blocks transactions artifact details served since startup on a Mithril aggregator node",
75        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
76    ),
77    proof_cardano_transaction_total_proofs_served_since_startup:MetricCounterWithLabels(
78        "mithril_aggregator_proof_cardano_transaction_total_proofs_served_since_startup",
79        "Number of Cardano transaction proofs served since startup on a Mithril aggregator node",
80        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
81    ),
82    proof_cardano_transaction_total_transactions_served_since_startup:MetricCounterWithLabels(
83        "mithril_aggregator_proof_cardano_transaction_total_transactions_served_since_startup",
84        "Number of Cardano transaction hashes requested for proof since startup on a Mithril aggregator node",
85        &[CLIENT_ORIGIN_TAG_LABEL, CLIENT_TYPE_LABEL]
86    ),
87    signer_registration_total_received_since_startup:MetricCounterWithLabels(
88        "mithril_aggregator_signer_registration_total_received_since_startup",
89        "Number of signer registrations received since startup on a Mithril aggregator node",
90        &[SIGNER_REGISTRATION_ORIGIN_TAG_LABEL]
91    ),
92    signer_registration_total_successful_since_startup:MetricCounterWithLabels(
93        "mithril_aggregator_signer_registration_total_successful_since_startup",
94        "Number of successful signer registrations received since startup on a Mithril aggregator node",
95        &[SIGNER_REGISTRATION_ORIGIN_TAG_LABEL]
96    ),
97    signature_registration_total_received_since_startup:MetricCounterWithLabels(
98        "mithril_aggregator_signature_registration_total_received_since_startup",
99        "Number of signature registrations received since startup on a Mithril aggregator node",
100        &[SIGNER_SIGNATURE_ORIGIN_TAG_LABEL]
101    ),
102    signature_registration_total_successful_since_startup:MetricCounterWithLabels(
103        "mithril_aggregator_signature_registration_total_successful_since_startup",
104        "Number of successful signature registrations received since startup on a Mithril aggregator node",
105        &[SIGNER_SIGNATURE_ORIGIN_TAG_LABEL]
106    ),
107    certificate_total_produced_since_startup:MetricCounter(
108        "mithril_aggregator_certificate_total_produced_since_startup",
109        "Number of certificates produced since startup on a Mithril aggregator node"
110    ),
111    artifact_cardano_immutable_files_full_total_produced_since_startup:MetricCounter(
112        "mithril_aggregator_artifact_cardano_db_total_produced_since_startup",
113        "Number of Cardano immutable files full artifacts produced since startup on a Mithril aggregator node"
114    ),
115    artifact_cardano_database_total_produced_since_startup:MetricCounter(
116        "mithril_aggregator_artifact_cardano_database_total_produced_since_startup",
117        "Number of Cardano database artifacts produced since startup on a Mithril aggregator node"
118    ),
119    artifact_mithril_stake_distribution_total_produced_since_startup:MetricCounter(
120        "mithril_aggregator_artifact_mithril_stake_distribution_total_produced_since_startup",
121        "Number of Mithril stake distribution artifacts produced since startup on a Mithril aggregator node"
122    ),
123    artifact_cardano_stake_distribution_total_produced_since_startup:MetricCounter(
124        "mithril_aggregator_artifact_cardano_stake_distribution_total_produced_since_startup",
125        "Number of Cardano stake distribution artifacts produced since startup on a Mithril aggregator node"
126    ),
127    artifact_cardano_transaction_total_produced_since_startup:MetricCounter(
128        "mithril_aggregator_artifact_cardano_transaction_total_produced_since_startup",
129        "Number of Cardano transaction artifacts produced since startup on a Mithril aggregator node"
130    ),
131    artifact_cardano_blocks_transactions_total_produced_since_startup:MetricCounter(
132        "mithril_aggregator_artifact_cardano_blocks_transactions_total_produced_since_startup",
133        "Number of Cardano blocks transactions artifacts produced since startup on a Mithril aggregator node"
134    ),
135    runtime_cycle_success_since_startup:MetricCounter(
136        "mithril_aggregator_runtime_cycle_success_since_startup",
137        "Number of successful runtime cycles since startup on a Mithril aggregator"
138    ),
139    runtime_cycle_total_since_startup:MetricCounter(
140        "mithril_aggregator_runtime_cycle_total_since_startup",
141        "Number of runtime cycles since startup on a Mithril aggregator"
142    )
143
144);
145
146impl MetricsService {
147    /// Export metrics in map.
148    pub fn export_metrics_map(&self) -> HashMap<String, HashMap<String, MetricLabelValueMap>> {
149        self.registry
150            .gather()
151            .iter()
152            .map(|metric_family| {
153                (
154                    metric_family.name().to_string(),
155                    self.build_metric_map(metric_family),
156                )
157            })
158            .collect()
159    }
160
161    fn build_label_key(&self, labels: &[LabelPair]) -> String {
162        labels.iter().map(|p| p.value()).collect::<Vec<_>>().join(",")
163    }
164
165    fn build_metric_map(
166        &self,
167        metric_family: &MetricFamily,
168    ) -> HashMap<String, MetricLabelValueMap> {
169        metric_family
170            .get_metric()
171            .iter()
172            .map(|m| {
173                (
174                    self.build_label_key(m.get_label()),
175                    MetricLabelValueMap::new(m.clone()),
176                )
177            })
178            .collect()
179    }
180}
181
182type LabelName = String;
183type LabelValue = String;
184
185#[derive(Debug, Clone, PartialEq, Eq)]
186/// [MetricLabelValueMap] represent a metric with a label_value_map and a counter.
187pub struct MetricLabelValueMap {
188    /// HashMap of label names and their corresponding values (eg. `{"origin_tag": "HTTP", "client_type": "CLI"}`).
189    pub label_value_map: HashMap<LabelName, LabelValue>,
190    /// Counter value of the metric
191    pub counter: i32,
192}
193
194impl MetricLabelValueMap {
195    /// Create a new MetricMap from a Metric Promotheus Metric.
196    pub fn new(metric: Metric) -> Self {
197        Self {
198            label_value_map: metric
199                .get_label()
200                .iter()
201                .map(|label| (label.name().to_string(), label.value().to_string()))
202                .collect(),
203            counter: metric.get_counter().as_ref().unwrap_or_default().value() as i32,
204        }
205    }
206}
207
208impl Default for MetricLabelValueMap {
209    /// Create a new MetricMap with an empty key_value map and a counter set to 0.
210    fn default() -> Self {
211        Self {
212            label_value_map: HashMap::new(),
213            counter: 0,
214        }
215    }
216}
217
218#[cfg(test)]
219mod tests {
220    use crate::test::TestLogger;
221
222    use super::*;
223
224    #[test]
225    fn should_export_counter_metrics_in_a_map() {
226        let metrics_service = MetricsService::new(TestLogger::stdout()).unwrap();
227        let metric_a = metrics_service.get_runtime_cycle_total_since_startup();
228        let metric_b = metrics_service.get_certificate_total_produced_since_startup();
229        metric_a.increment_by(5);
230        metric_b.increment_by(12);
231
232        let export = metrics_service.export_metrics_map();
233        assert_eq!(5, export[&metric_a.name()][""].counter);
234        assert_eq!(12, export[&metric_b.name()][""].counter);
235    }
236
237    #[test]
238    fn should_export_counter_metrics_with_label_in_a_map() {
239        let metrics_service = MetricsService::new(TestLogger::stdout()).unwrap();
240        let metric_a = metrics_service.get_certificate_detail_total_served_since_startup();
241        metric_a.increment_by(&["A", "B"], 5);
242        metric_a.increment_by(&["1", "2"], 12);
243
244        let export = metrics_service.export_metrics_map();
245
246        let metric_a_token_a_b = export[&metric_a.name()]["B,A"].clone();
247        let metric_a_token_1_2 = export[&metric_a.name()]["2,1"].clone();
248
249        assert_eq!(5, metric_a_token_a_b.to_owned().counter);
250        assert_eq!(
251            "A",
252            metric_a_token_a_b.to_owned().label_value_map["origin_tag"]
253        );
254        assert_eq!(
255            "B",
256            metric_a_token_a_b.to_owned().label_value_map["client_type"]
257        );
258
259        assert_eq!(12, metric_a_token_1_2.to_owned().counter);
260        assert_eq!(
261            "1",
262            metric_a_token_1_2.to_owned().label_value_map["origin_tag"]
263        );
264        assert_eq!(
265            "2",
266            metric_a_token_1_2.to_owned().label_value_map["client_type"]
267        );
268    }
269
270    #[test]
271    fn should_export_several_times_and_counter_return_values_since_start() {
272        let metrics_service = MetricsService::new(TestLogger::stdout()).unwrap();
273        let metric_a = metrics_service.get_runtime_cycle_total_since_startup();
274        metric_a.increment_by(5);
275
276        let export = metrics_service.export_metrics_map();
277        assert_eq!(5, export[&metric_a.name()][""].counter);
278
279        metric_a.increment();
280        let export = metrics_service.export_metrics_map();
281        assert_eq!(6, export[&metric_a.name()][""].counter);
282    }
283
284    #[test]
285    fn should_export_counter_even_the_value_is_0() {
286        let metrics_service = MetricsService::new(TestLogger::stdout()).unwrap();
287        let metric_a = metrics_service.get_runtime_cycle_total_since_startup();
288
289        let export = metrics_service.export_metrics_map();
290        assert_eq!(0, export[&metric_a.name()][""].counter);
291    }
292
293    #[test]
294    fn metric_service_should_only_contain_counters_as_export_metrics_map_does_not_yet_support_other_types()
295     {
296        let metrics_service = MetricsService::new(TestLogger::stdout()).unwrap();
297
298        for metric_family in metrics_service.registry.gather() {
299            for metric in metric_family.get_metric() {
300                assert!(metric.get_counter().is_some());
301            }
302        }
303    }
304}