diff --git a/Cargo.lock b/Cargo.lock index a8cf6b4..70eb786 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6594,6 +6594,7 @@ dependencies = [ "metrics", "miner", "network", + "parking_lot 0.12.3", "serde", "serde_json", "shared_types", diff --git a/node/rpc/Cargo.toml b/node/rpc/Cargo.toml index 287fcc6..390a371 100644 --- a/node/rpc/Cargo.toml +++ b/node/rpc/Cargo.toml @@ -27,3 +27,4 @@ merkle_light = { path = "../../common/merkle_light" } merkle_tree = { path = "../../common/merkle_tree"} futures-channel = "^0.3" metrics = { workspace = true } +parking_lot = "0.12.3" diff --git a/node/rpc/src/lib.rs b/node/rpc/src/lib.rs index a719ee7..3f9c212 100644 --- a/node/rpc/src/lib.rs +++ b/node/rpc/src/lib.rs @@ -6,6 +6,7 @@ extern crate miner as zgs_miner; mod admin; mod config; mod error; +mod middleware; mod miner; pub mod types; mod zgs; @@ -77,8 +78,10 @@ pub async fn run_server( Ok(handles) } -fn server_builder(ctx: Context) -> HttpServerBuilder { - HttpServerBuilder::default().max_request_body_size(ctx.config.max_request_body_size) +fn server_builder(ctx: Context) -> HttpServerBuilder { + HttpServerBuilder::default() + .max_request_body_size(ctx.config.max_request_body_size) + .set_middleware(middleware::Metrics::default()) } /// Run a single RPC server for all namespace RPCs. diff --git a/node/rpc/src/middleware.rs b/node/rpc/src/middleware.rs new file mode 100644 index 0000000..808acc5 --- /dev/null +++ b/node/rpc/src/middleware.rs @@ -0,0 +1,50 @@ +use std::{collections::HashMap, sync::Arc, time::Instant}; + +use jsonrpsee::core::middleware::Middleware; +use metrics::{register_meter_with_group, Histogram, Meter, Sample}; +use parking_lot::RwLock; + +struct RpcMetric { + qps: Arc, + latency: Arc, +} + +impl RpcMetric { + fn new(method_name: &String) -> Self { + let group = format!("rpc_{}", method_name); + + Self { + qps: register_meter_with_group(group.as_str(), "qps"), + latency: Sample::ExpDecay(0.015).register_with_group(group.as_str(), "latency", 1024), + } + } +} + +#[derive(Clone, Default)] +pub struct Metrics { + metrics_by_method: Arc>>, +} + +impl Middleware for Metrics { + type Instant = Instant; + + fn on_request(&self) -> Self::Instant { + Instant::now() + } + + fn on_call(&self, name: &str) { + let mut metrics_by_method = self.metrics_by_method.write(); + let entry = metrics_by_method + .entry(name.to_string()) + .or_insert_with_key(RpcMetric::new); + entry.qps.mark(1); + } + + fn on_result(&self, name: &str, _success: bool, started_at: Self::Instant) { + let mut metrics_by_method = self.metrics_by_method.write(); + let entry = metrics_by_method + .entry(name.to_string()) + .or_insert_with_key(RpcMetric::new); + entry.latency.update_since(started_at); + } +}