Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(middleware): create a generic middleware to collect method metrics. #804

Merged
merged 10 commits into from
Sep 26, 2024
Merged
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions crates/pool/src/server/remote/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ use std::{
use async_trait::async_trait;
use ethers::types::{Address, H256};
use futures_util::StreamExt;
use rundler_task::grpc::{metrics::GrpcMetricsLayer, protos::from_bytes};
use rundler_task::{
grpc::{grpc_metrics::HttpMethodExtractor, protos::from_bytes},
metrics::{MetricsLayer, RequestMethodNameInfo},
};
use rundler_types::{
chain::ChainSpec,
pool::{Pool, Reputation},
Expand Down Expand Up @@ -78,7 +81,7 @@ pub(crate) async fn spawn_remote_mempool_server(
.set_serving::<OpPoolServer<OpPoolImpl>>()
.await;

let metrics_layer = GrpcMetricsLayer::new("op_pool".to_string());
let metrics_layer = MetricsLayer::<HttpMethodExtractor, http::Request>::new("op_pool_service".to_string(), "http-grpc".to_string());
let handle = tokio::spawn(async move {
Server::builder()
.layer(metrics_layer)
Expand Down
33 changes: 33 additions & 0 deletions crates/provider/src/traits/metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// This file is part of Rundler.
//
// Rundler is free software: you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later version.
//
// Rundler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Rundler.
// If not, see https://www.gnu.org/licenses/.

/// Method extractor
use rundler_types::task::traits::RequestExtractor;
use alloy_json_rpc::RequestPacket;

#[derive(Clone, Copy)]
struct AlloyMethodExtractor;

impl RequestExtractor<RequestPacket> for RPCMethodExtractor {
fn get_method_name(req: &RequestPacket) -> String {
match req {
RequestPacket::Single(request) => {
request.method().to_string()
}
_ => {
// can't extract method name for batch.
"unknown".to_string()
andysim3d marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
2 changes: 1 addition & 1 deletion crates/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ mod eth;
pub use eth::{EthApiClient, EthApiSettings};

mod health;
mod metrics;
mod rpc_metrics;

mod rundler;
pub use rundler::{RundlerApiClient, Settings as RundlerApiSettings};
Expand Down
145 changes: 0 additions & 145 deletions crates/rpc/src/metrics.rs

This file was deleted.

24 changes: 24 additions & 0 deletions crates/rpc/src/rpc_metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// This file is part of Rundler.
//
// Rundler is free software: you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later version.
//
// Rundler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Rundler.
// If not, see https://www.gnu.org/licenses/.

use jsonrpsee::types::Request;
use rundler_types::task::traits::RequestExtractor;

#[derive(Copy)]
andysim3d marked this conversation as resolved.
Show resolved Hide resolved
struct RPCMethodExtractor;

impl RequestExtractor<Request> for RPCMethodExtractor {
fn get_method_name(req: &Request) -> String {
req.method_name().to_string()
}
}
13 changes: 7 additions & 6 deletions crates/rpc/src/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ use std::{net::SocketAddr, sync::Arc, time::Duration};
use anyhow::{bail, Context};
use async_trait::async_trait;
use jsonrpsee::{
server::{middleware::http::ProxyGetRequestLayer, RpcServiceBuilder, ServerBuilder},
RpcModule,
server::{middleware::http::ProxyGetRequestLayer, RpcServiceBuilder, ServerBuilder}, types::Request, RpcModule
};
use rundler_provider::{EntryPointProvider, Provider};
use rundler_sim::{
EstimationSettings, FeeEstimator, GasEstimatorV0_6, GasEstimatorV0_7, PrecheckSettings,
};
use rundler_task::{
metrics::MetricsLayer,
server::{format_socket_addr, HealthCheck},
Task,
};
Expand All @@ -42,9 +42,10 @@ use crate::{
EthApiSettings, UserOperationEventProviderV0_6, UserOperationEventProviderV0_7,
},
health::{HealthChecker, SystemApiServer},
metrics::RpcMetricsMiddlewareLayer,
rpc_metrics,
rundler::{RundlerApi, RundlerApiServer, Settings as RundlerApiSettings},
types::ApiNamespace,
rpc_metrics::RPCMethodExtractor,
};

/// RPC server arguments.
Expand Down Expand Up @@ -186,12 +187,12 @@ where
.layer(ProxyGetRequestLayer::new("/health", "system_health")?)
.timeout(self.args.rpc_timeout);

let rpc_middleware =
RpcServiceBuilder::new().layer(RpcMetricsMiddlewareLayer::new(&module));
let rpc_metric_middleware =
MetricsLayer::<RPCMethodExtractor, Request>::new("rundler-eth-service".to_string(), "rpc".to_string());

let server = ServerBuilder::default()
.set_http_middleware(http_middleware)
.set_rpc_middleware(rpc_middleware)
.set_rpc_middleware(rpc_metric_middleware)
.max_connections(self.args.max_connections)
// Set max request body size to 2x the max transaction size as none of our
// APIs should require more than that.
Expand Down
2 changes: 1 addition & 1 deletion crates/task/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ publish = false
[dependencies]
rundler-provider = { path = "../provider" }
rundler-utils = { path = "../utils" }
rundler-types = { path = "../types" }

alloy-primitives.workspace = true

anyhow.workspace = true
async-trait.workspace = true
futures.workspace = true
pin-project.workspace = true
metrics.workspace = true
tokio.workspace = true
tokio-util.workspace = true
Expand Down
26 changes: 26 additions & 0 deletions crates/task/src/grpc/grpc_metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// This file is part of Rundler.
//
// Rundler is free software: you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later version.
//
// Rundler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with Rundler.
// If not, see https://www.gnu.org/licenses/.

use rundler_types::task::traits::RequestExtractor;
use tonic::codegen::http;

/// http request method extractor.
#[derive(Copy, Clone)]
struct HttpMethodExtractor;

impl<Body> RequestExtractor<http::Request<Body>> for HttpMethodExtractor {
fn get_method_name(req: &http::Request<Body>) -> String {
let method_name = req.uri().path().split('/').last().unwrap_or("unknown");
method_name.to_string()
}
}
Loading
Loading