Example: logging_layer
Example
To run this example:
- Clone the examples repository:
git clone git@github.com:alloy-rs/examples.git
- Run:
cargo run --example logging_layer
//! This examples demonstrates how to implement your own custom transport layer.
//! As a demonstration we implement a simple request / response logging layer.
use std::{
fmt::Debug,
future::{Future, IntoFuture},
pin::Pin,
task::{Context, Poll},
};
use alloy::{
node_bindings::Anvil,
providers::{Provider, ProviderBuilder},
rpc::{
client::ClientBuilder,
json_rpc::{RequestPacket, ResponsePacket},
},
transports::TransportError,
};
use eyre::Result;
use tower::{Layer, Service};
struct LoggingLayer;
// Implement tower::Layer for LoggingLayer.
impl<S> Layer<S> for LoggingLayer {
type Service = LoggingService<S>;
fn layer(&self, inner: S) -> Self::Service {
LoggingService { inner }
}
}
// A logging service that wraps an inner service.
#[derive(Debug, Clone)]
struct LoggingService<S> {
inner: S,
}
// Implement tower::Service for LoggingService.
impl<S> Service<RequestPacket> for LoggingService<S>
where
// Constraints on the service.
S: Service<RequestPacket, Response = ResponsePacket, Error = TransportError>,
S::Future: Send + 'static,
S::Response: Send + 'static + Debug,
S::Error: Send + 'static + Debug,
{
type Response = S::Response;
type Error = S::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.inner.poll_ready(cx)
}
fn call(&mut self, req: RequestPacket) -> Self::Future {
println!("Request: {req:?}");
let fut = self.inner.call(req);
Box::pin(async move {
let res = fut.await;
println!("Response: {res:?}");
res
})
}
}
#[tokio::main]
async fn main() -> Result<()> {
// Spin up a local Anvil node.
// Ensure `anvil` is available in $PATH.
let anvil = Anvil::new().spawn();
// Create a new client with the logging layer.
let rpc_url = anvil.endpoint_url();
let client = ClientBuilder::default().layer(LoggingLayer).http(rpc_url);
// Create a new provider with the client.
let provider = ProviderBuilder::new().on_client(client);
for _ in 0..10 {
let _block_number = provider.get_block_number().into_future().await?;
}
Ok(())
}
Find the source code on Github here.