diff --git a/src/main/kotlin/io/emeraldpay/dshackle/proxy/HttpHandler.kt b/src/main/kotlin/io/emeraldpay/dshackle/proxy/HttpHandler.kt index 6ebe5177..b5aa5e29 100644 --- a/src/main/kotlin/io/emeraldpay/dshackle/proxy/HttpHandler.kt +++ b/src/main/kotlin/io/emeraldpay/dshackle/proxy/HttpHandler.kt @@ -41,7 +41,7 @@ class HttpHandler( writeRpcJson: WriteRpcJson, nativeCall: NativeCall, private val accessHandler: AccessHandlerHttp.HandlerFactory, - requestMetrics: ProxyServer.RequestMetricsFactory, + private val requestMetrics: ProxyServer.RequestMetricsFactory, ) : BaseHandler(writeRpcJson, nativeCall, requestMetrics) { companion object { @@ -70,6 +70,13 @@ class HttpHandler( ): Flux { return request .map(readRpcJson) + .doOnError { + log.debug("Failed to process request JSON with: ${it.javaClass} ${it.message}") + // most of the metrics are handled inside the execute method, including most of the errors. + // but if we have an invalid JSON it stops here, and we cannot handle it in the main onErrorResume + // because it's going to be a duplicate call for other errors + requestMetrics.get(chain, "invalid_method").errorMetric.increment() + } .flatMapMany { call -> execute(chain, call, handler) } diff --git a/src/test/groovy/io/emeraldpay/dshackle/proxy/HttpHandlerSpec.groovy b/src/test/groovy/io/emeraldpay/dshackle/proxy/HttpHandlerSpec.groovy index 59b1d211..e6725ddf 100644 --- a/src/test/groovy/io/emeraldpay/dshackle/proxy/HttpHandlerSpec.groovy +++ b/src/test/groovy/io/emeraldpay/dshackle/proxy/HttpHandlerSpec.groovy @@ -23,6 +23,8 @@ import io.emeraldpay.dshackle.rpc.NativeCall import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse import io.emeraldpay.etherjar.rpc.RpcException import io.emeraldpay.grpc.Chain +import io.micrometer.core.instrument.Counter +import io.micrometer.core.instrument.step.StepCounter import reactor.core.publisher.Flux import reactor.core.publisher.Mono import reactor.test.StepVerifier @@ -72,10 +74,19 @@ class HttpHandlerSpec extends Specification { ReadRpcJson read = Mock(ReadRpcJson) { 1 * apply(_) >> { throw new RpcException(-32123, "test", new JsonRpcResponse.NumberId(4)) } } + Counter errorMetric = Mock(Counter) { + 1 * increment() + } + ProxyServer.RequestMetricsFactory metrics = Mock(ProxyServer.RequestMetricsFactory) { + 1 * get(Chain.ETHEREUM, "invalid_method") >> Mock(ProxyServer.RequestMetrics) { + 1 * it.errorMetric >> errorMetric + } + } def handler = new HttpHandler( read, new WriteRpcJson(), - Stub(NativeCall), Stub(AccessHandlerHttp.HandlerFactory), Stub(ProxyServer.RequestMetricsFactory) + Stub(NativeCall), Stub(AccessHandlerHttp.HandlerFactory), + metrics ) when: