soil_rpc/v2/transaction/
metrics.rs1use std::{collections::HashSet, time::Instant};
10
11use soil_prometheus::{
12 exponential_buckets, linear_buckets, register, Histogram, HistogramOpts, PrometheusError,
13 Registry,
14};
15
16use super::TransactionEvent;
17
18#[derive(Debug, Clone)]
20pub struct Metrics {
21 validated: Histogram,
22 in_block: Histogram,
23 finalized: Histogram,
24 dropped: Histogram,
25 invalid: Histogram,
26 error: Histogram,
27}
28
29impl Metrics {
30 pub fn new(registry: &Registry) -> Result<Self, PrometheusError> {
32 let validated = register(
33 Histogram::with_opts(
34 HistogramOpts::new(
35 "rpc_transaction_validation_time",
36 "RPC Transaction validation time in seconds",
37 )
38 .buckets(exponential_buckets(0.01, 2.0, 16).expect("Valid buckets; qed")),
39 )?,
40 registry,
41 )?;
42
43 let in_block = register(
44 Histogram::with_opts(
45 HistogramOpts::new(
46 "rpc_transaction_in_block_time",
47 "RPC Transaction in block time in seconds",
48 )
49 .buckets(linear_buckets(0.0, 3.0, 20).expect("Valid buckets; qed")),
50 )?,
51 registry,
52 )?;
53
54 let finalized = register(
55 Histogram::with_opts(
56 HistogramOpts::new(
57 "rpc_transaction_finalized_time",
58 "RPC Transaction finalized time in seconds",
59 )
60 .buckets(linear_buckets(0.01, 40.0, 20).expect("Valid buckets; qed")),
61 )?,
62 registry,
63 )?;
64
65 let dropped = register(
66 Histogram::with_opts(
67 HistogramOpts::new(
68 "rpc_transaction_dropped_time",
69 "RPC Transaction dropped time in seconds",
70 )
71 .buckets(linear_buckets(0.01, 3.0, 20).expect("Valid buckets; qed")),
72 )?,
73 registry,
74 )?;
75
76 let invalid = register(
77 Histogram::with_opts(
78 HistogramOpts::new(
79 "rpc_transaction_invalid_time",
80 "RPC Transaction invalid time in seconds",
81 )
82 .buckets(linear_buckets(0.01, 3.0, 20).expect("Valid buckets; qed")),
83 )?,
84 registry,
85 )?;
86
87 let error = register(
88 Histogram::with_opts(
89 HistogramOpts::new(
90 "rpc_transaction_error_time",
91 "RPC Transaction error time in seconds",
92 )
93 .buckets(linear_buckets(0.01, 3.0, 20).expect("Valid buckets; qed")),
94 )?,
95 registry,
96 )?;
97
98 Ok(Metrics { validated, in_block, finalized, dropped, invalid, error })
99 }
100}
101
102pub struct InstanceMetrics {
104 metrics: Option<Metrics>,
106 submitted_at: Instant,
108 reported_states: HashSet<&'static str>,
110}
111
112impl InstanceMetrics {
113 pub fn new(metrics: Option<Metrics>) -> Self {
115 Self { metrics, submitted_at: Instant::now(), reported_states: HashSet::new() }
116 }
117
118 pub fn register_event<Hash>(&mut self, event: &TransactionEvent<Hash>) {
124 let Some(ref metrics) = self.metrics else {
125 return;
126 };
127
128 let (histogram, target_state) = match event {
129 TransactionEvent::Validated => (&metrics.validated, "validated"),
130 TransactionEvent::BestChainBlockIncluded(Some(_)) => (&metrics.in_block, "in_block"),
131 TransactionEvent::BestChainBlockIncluded(None) => (&metrics.in_block, "retracted"),
132 TransactionEvent::Finalized(..) => (&metrics.finalized, "finalized"),
133 TransactionEvent::Error(..) => (&metrics.error, "error"),
134 TransactionEvent::Dropped(..) => (&metrics.dropped, "dropped"),
135 TransactionEvent::Invalid(..) => (&metrics.invalid, "invalid"),
136 };
137
138 if self.reported_states.insert(target_state) {
140 histogram.observe(self.submitted_at.elapsed().as_secs_f64());
141 }
142 }
143}