forest/rpc/
metrics_layer.rs1use crate::metrics;
5use jsonrpsee::MethodResponse;
6use jsonrpsee::core::middleware::{Batch, Notification};
7use jsonrpsee::server::middleware::rpc::RpcServiceT;
8use tower::Layer;
9
10#[derive(Clone, Default)]
12pub(super) struct MetricsLayer {}
13
14impl<S> Layer<S> for MetricsLayer {
15 type Service = RecordMetrics<S>;
16
17 fn layer(&self, service: S) -> Self::Service {
18 RecordMetrics { service }
19 }
20}
21
22#[derive(Clone)]
23pub(super) struct RecordMetrics<S> {
24 service: S,
25}
26
27impl<S> RecordMetrics<S> {
28 async fn log<F>(method: String, future: F) -> MethodResponse
29 where
30 F: Future<Output = MethodResponse>,
31 {
32 let method = metrics::RpcMethodLabel { method };
33 let start_time = std::time::Instant::now();
34 let resp = future.await;
35 metrics::RPC_METHOD_TIME
36 .get_or_create(&method)
37 .observe(start_time.elapsed().as_secs_f64() * 1000.0);
39 if resp.is_error() {
40 metrics::RPC_METHOD_FAILURE.get_or_create(&method).inc();
41 }
42 resp
43 }
44}
45
46impl<S> RpcServiceT for RecordMetrics<S>
47where
48 S: RpcServiceT<MethodResponse = MethodResponse, NotificationResponse = MethodResponse>
49 + Send
50 + Sync
51 + Clone
52 + 'static,
53{
54 type MethodResponse = S::MethodResponse;
55 type NotificationResponse = S::NotificationResponse;
56 type BatchResponse = S::BatchResponse;
57
58 fn call<'a>(
59 &self,
60 req: jsonrpsee::types::Request<'a>,
61 ) -> impl Future<Output = Self::MethodResponse> + Send + 'a {
62 Self::log(req.method_name().to_owned(), self.service.call(req))
63 }
64
65 fn batch<'a>(&self, batch: Batch<'a>) -> impl Future<Output = Self::BatchResponse> + Send + 'a {
66 self.service.batch(batch)
67 }
68
69 fn notification<'a>(
70 &self,
71 n: Notification<'a>,
72 ) -> impl Future<Output = Self::NotificationResponse> + Send + 'a {
73 Self::log(n.method_name().to_owned(), self.service.notification(n))
74 }
75}