use jsonrpsee::{
server::middleware::rpc::{layer::ResponseFuture, RpcServiceT},
MethodResponse,
};
use tracing::{info_span, Instrument};
#[derive(Clone)]
pub struct RpcTracingMiddleware<S> {
service: S,
}
impl<S> RpcTracingMiddleware<S> {
pub fn new(service: S) -> Self {
Self { service }
}
}
impl<'a, S> RpcServiceT<'a> for RpcTracingMiddleware<S>
where
S: RpcServiceT<'a> + Send + Sync + Clone + 'static,
{
type Future = ResponseFuture<futures::future::BoxFuture<'a, MethodResponse>>;
fn call(&self, request: jsonrpsee::types::Request<'a>) -> Self::Future {
let service = self.service.clone();
let method = request.method_name().to_owned();
let span = info_span!(
"rpc_request",
otel.kind = "server",
rpc.method = %method,
rpc.system = "jsonrpc",
otel.status_code = tracing::field::Empty,
rpc.error_code = tracing::field::Empty,
);
let span_for_record = span.clone();
ResponseFuture::future(Box::pin(
async move {
let response = service.call(request).await;
if response.is_error() {
span_for_record.record("otel.status_code", "ERROR");
if let Some(error_code) = response.as_error_code() {
span_for_record.record("rpc.error_code", error_code);
}
}
response
}
.instrument(span),
))
}
}