jsonrpsee_server/middleware/rpc/layer/
logger.rs

1// Copyright 2019-2021 Parity Technologies (UK) Ltd.
2//
3// Permission is hereby granted, free of charge, to any
4// person obtaining a copy of this software and associated
5// documentation files (the "Software"), to deal in the
6// Software without restriction, including without
7// limitation the rights to use, copy, modify, merge,
8// publish, distribute, sublicense, and/or sell copies of
9// the Software, and to permit persons to whom the Software
10// is furnished to do so, subject to the following
11// conditions:
12//
13// The above copyright notice and this permission notice
14// shall be included in all copies or substantial portions
15// of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25// DEALINGS IN THE SOFTWARE.
26
27//! RPC Logger layer.
28
29use std::{
30	pin::Pin,
31	task::{Context, Poll},
32};
33
34use futures_util::Future;
35use jsonrpsee_core::{
36	server::MethodResponse,
37	tracing::server::{rx_log_from_json, tx_log_from_str},
38};
39use jsonrpsee_types::Request;
40use pin_project::pin_project;
41use tracing::{instrument::Instrumented, Instrument};
42
43use crate::middleware::rpc::RpcServiceT;
44
45/// RPC logger layer.
46#[derive(Copy, Clone, Debug)]
47pub struct RpcLoggerLayer(u32);
48
49impl RpcLoggerLayer {
50	/// Create a new logging layer.
51	pub fn new(max: u32) -> Self {
52		Self(max)
53	}
54}
55
56impl<S> tower::Layer<S> for RpcLoggerLayer {
57	type Service = RpcLogger<S>;
58
59	fn layer(&self, service: S) -> Self::Service {
60		RpcLogger { service, max: self.0 }
61	}
62}
63
64/// A middleware that logs each RPC call and response.
65#[derive(Debug)]
66pub struct RpcLogger<S> {
67	max: u32,
68	service: S,
69}
70
71impl<'a, S> RpcServiceT<'a> for RpcLogger<S>
72where
73	S: RpcServiceT<'a>,
74{
75	type Future = Instrumented<ResponseFuture<S::Future>>;
76
77	#[tracing::instrument(name = "method_call", skip_all, fields(method = request.method_name()), level = "trace")]
78	fn call(&self, request: Request<'a>) -> Self::Future {
79		rx_log_from_json(&request, self.max);
80
81		ResponseFuture { fut: self.service.call(request), max: self.max }.in_current_span()
82	}
83}
84
85/// Response future to log the response for a method call.
86#[pin_project]
87pub struct ResponseFuture<F> {
88	#[pin]
89	fut: F,
90	max: u32,
91}
92
93impl<F> std::fmt::Debug for ResponseFuture<F> {
94	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95		f.write_str("ResponseFuture")
96	}
97}
98
99impl<F: Future<Output = MethodResponse>> Future for ResponseFuture<F> {
100	type Output = F::Output;
101
102	fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
103		let max = self.max;
104		let fut = self.project().fut;
105
106		let res = fut.poll(cx);
107		if let Poll::Ready(rp) = &res {
108			tx_log_from_str(rp.as_result(), max);
109		}
110		res
111	}
112}