1use std::time::Duration;
10
11use iota_network_stack::metrics::MetricsCallbackProvider;
12use prometheus::{
13 HistogramVec, IntCounterVec, IntGauge, IntGaugeVec, Registry,
14 register_histogram_vec_with_registry, register_int_counter_vec_with_registry,
15 register_int_gauge_vec_with_registry, register_int_gauge_with_registry,
16};
17use tonic::Code;
18
19#[derive(Clone, Debug)]
21pub struct RequestMetrics {
22 pub(crate) total_requests_received: IntCounterVec,
23 pub(crate) total_requests_succeeded: IntCounterVec,
24 pub(crate) total_requests_shed: IntCounterVec,
25 pub(crate) total_requests_failed: IntCounterVec,
26 pub(crate) total_requests_disconnected: IntCounterVec,
27 pub(crate) current_requests_in_flight: IntGaugeVec,
28 pub(crate) process_latency: HistogramVec,
29}
30
31#[derive(Clone, Debug)]
33pub struct FaucetMetrics {
34 pub(crate) current_executions_in_flight: IntGauge,
35 pub(crate) total_available_coins: IntGauge,
36 pub(crate) total_discarded_coins: IntGauge,
37 pub(crate) total_coin_requests_succeeded: IntGauge,
38}
39
40const LATENCY_SEC_BUCKETS: &[f64] = &[
41 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1., 2.5, 5., 10., 20., 30., 60., 90.,
42];
43
44impl RequestMetrics {
45 pub fn new(registry: &Registry) -> Self {
46 Self {
47 total_requests_received: register_int_counter_vec_with_registry!(
48 "total_requests_received",
49 "Total number of requests received in Faucet",
50 &["path"],
51 registry,
52 )
53 .unwrap(),
54 total_requests_succeeded: register_int_counter_vec_with_registry!(
55 "total_requests_succeeded",
56 "Total number of requests processed successfully in Faucet",
57 &["path"],
58 registry,
59 )
60 .unwrap(),
61 total_requests_shed: register_int_counter_vec_with_registry!(
62 "total_requests_shed",
63 "Total number of requests that were dropped because the service was saturated",
64 &["path"],
65 registry,
66 )
67 .unwrap(),
68 total_requests_failed: register_int_counter_vec_with_registry!(
69 "total_requests_failed",
70 "Total number of requests that started but failed with an uncaught error",
71 &["path"],
72 registry,
73 )
74 .unwrap(),
75 total_requests_disconnected: register_int_counter_vec_with_registry!(
76 "total_requests_disconnected",
77 "Total number of requests where the client disconnected before the service \
78 returned a response",
79 &["path"],
80 registry,
81 )
82 .unwrap(),
83 current_requests_in_flight: register_int_gauge_vec_with_registry!(
84 "current_requests_in_flight",
85 "Current number of requests being processed in Faucet",
86 &["path"],
87 registry,
88 )
89 .unwrap(),
90 process_latency: register_histogram_vec_with_registry!(
91 "process_latency",
92 "Latency of processing a Faucet request",
93 &["path"],
94 LATENCY_SEC_BUCKETS.to_vec(),
95 registry,
96 )
97 .unwrap(),
98 }
99 }
100}
101
102impl FaucetMetrics {
103 pub fn new(registry: &Registry) -> Self {
104 Self {
105 current_executions_in_flight: register_int_gauge_with_registry!(
106 "current_executions_in_flight",
107 "Current number of transactions being executed in Faucet",
108 registry,
109 )
110 .unwrap(),
111 total_available_coins: register_int_gauge_with_registry!(
112 "total_available_coins",
113 "Total number of available coins in queue",
114 registry,
115 )
116 .unwrap(),
117 total_discarded_coins: register_int_gauge_with_registry!(
118 "total_discarded_coins",
119 "Total number of discarded coins",
120 registry,
121 )
122 .unwrap(),
123 total_coin_requests_succeeded: register_int_gauge_with_registry!(
124 "total_coin_requests_succeeded",
125 "Total number of requests processed successfully in Faucet (both batch and non_batched)",
126 registry,
127 )
128 .unwrap(),
129 }
130 }
131}
132
133impl MetricsCallbackProvider for RequestMetrics {
134 fn on_request(&self, path: String) {
135 self.total_requests_received
136 .with_label_values(&[path.as_str()])
137 .inc();
138 }
139
140 fn on_response(&self, path: String, latency: Duration, _status: u16, grpc_status_code: Code) {
141 self.process_latency
142 .with_label_values(&[path.as_str()])
143 .observe(latency.as_secs_f64());
144
145 match grpc_status_code {
146 Code::Ok => {
147 self.total_requests_succeeded
148 .with_label_values(&[path.as_str()])
149 .inc();
150 }
151 Code::Unavailable | Code::ResourceExhausted => {
152 self.total_requests_shed
153 .with_label_values(&[path.as_str()])
154 .inc();
155 }
156 _ => {
157 self.total_requests_failed
158 .with_label_values(&[path.as_str()])
159 .inc();
160 }
161 }
162 }
163
164 fn on_start(&self, path: &str) {
165 self.current_requests_in_flight
166 .with_label_values(&[path])
167 .inc();
168 }
169
170 fn on_drop(&self, path: &str) {
171 self.total_requests_disconnected
172 .with_label_values(&[path])
173 .inc();
174 self.current_requests_in_flight
175 .with_label_values(&[path])
176 .dec();
177 }
178}