diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cca0afdff7..0d7fdc02931 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ - Log detailed timing of block creation steps [#6880](https://github.com/hyperledger/besu/pull/6880) - Expose transaction count by type metrics for the layered txpool [#6903](https://github.com/hyperledger/besu/pull/6903) - Expose bad block events via the BesuEvents plugin API [#6848](https://github.com/hyperledger/besu/pull/6848) +- Add RPC errors metric [#6919](https://github.com/hyperledger/besu/pull/6919/) ### Bug fixes - Fix txpool dump/restore race condition [#6665](https://github.com/hyperledger/besu/pull/6665) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/EngineJsonRpcService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/EngineJsonRpcService.java index 567a8d3341b..e0279f6b7ce 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/EngineJsonRpcService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/EngineJsonRpcService.java @@ -149,6 +149,8 @@ public String get(final @Nullable HttpServerRequest carrier, final String key) { private final HealthService livenessService; private final HealthService readinessService; + private final MetricsSystem metricsSystem; + /** * Construct a EngineJsonRpcService to handle either http or websocket clients * @@ -214,6 +216,7 @@ public EngineJsonRpcService( this.livenessService = livenessService; this.readinessService = readinessService; this.maxActiveConnections = config.getMaxActiveConnections(); + this.metricsSystem = metricsSystem; } public CompletableFuture start() { @@ -451,7 +454,8 @@ private Router buildRouter() { new JsonRpcExecutor( new AuthenticatedJsonRpcProcessor( new TimedJsonRpcProcessor( - new TracedJsonRpcProcessor(new BaseJsonRpcProcessor()), requestTimer), + new TracedJsonRpcProcessor(new BaseJsonRpcProcessor(), metricsSystem), + requestTimer), authenticationService.get(), config.getNoAuthRpcApis()), rpcMethods), @@ -463,7 +467,8 @@ private Router buildRouter() { HandlerFactory.jsonRpcExecutor( new JsonRpcExecutor( new TimedJsonRpcProcessor( - new TracedJsonRpcProcessor(new BaseJsonRpcProcessor()), requestTimer), + new TracedJsonRpcProcessor(new BaseJsonRpcProcessor(), metricsSystem), + requestTimer), rpcMethods), tracer, config), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java index 1c8d7a2baf3..bcadf993d10 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcHttpService.java @@ -134,6 +134,7 @@ public String get(final @Nullable HttpServerRequest carrier, final String key) { private HttpServer httpServer; private final HealthService livenessService; private final HealthService readinessService; + private final MetricsSystem metricsSystem; /** * Construct a JsonRpcHttpService handler @@ -204,6 +205,7 @@ public JsonRpcHttpService( if (metricsSystem instanceof OpenTelemetrySystem) { this.tracerProvider = ((OpenTelemetrySystem) metricsSystem).getTracerProvider(); } + this.metricsSystem = metricsSystem; } private void validateConfig(final JsonRpcConfiguration config) { @@ -344,7 +346,8 @@ private Router buildRouter() { new JsonRpcExecutor( new AuthenticatedJsonRpcProcessor( new TimedJsonRpcProcessor( - new TracedJsonRpcProcessor(new BaseJsonRpcProcessor()), requestTimer), + new TracedJsonRpcProcessor(new BaseJsonRpcProcessor(), metricsSystem), + requestTimer), authenticationService.get(), config.getNoAuthRpcApis()), rpcMethods), @@ -356,7 +359,8 @@ private Router buildRouter() { HandlerFactory.jsonRpcExecutor( new JsonRpcExecutor( new TimedJsonRpcProcessor( - new TracedJsonRpcProcessor(new BaseJsonRpcProcessor()), requestTimer), + new TracedJsonRpcProcessor(new BaseJsonRpcProcessor(), metricsSystem), + requestTimer), rpcMethods), tracer, config), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java index ecde766f8b3..c40c8f8c1f6 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/execution/TracedJsonRpcProcessor.java @@ -20,6 +20,10 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponseType; +import org.hyperledger.besu.metrics.BesuMetricCategory; +import org.hyperledger.besu.plugin.services.MetricsSystem; +import org.hyperledger.besu.plugin.services.metrics.Counter; +import org.hyperledger.besu.plugin.services.metrics.LabelledMetric; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.StatusCode; @@ -27,9 +31,18 @@ public class TracedJsonRpcProcessor implements JsonRpcProcessor { private final JsonRpcProcessor rpcProcessor; + protected final LabelledMetric rpcErrorsCounter; - public TracedJsonRpcProcessor(final JsonRpcProcessor rpcProcessor) { + public TracedJsonRpcProcessor( + final JsonRpcProcessor rpcProcessor, final MetricsSystem metricsSystem) { this.rpcProcessor = rpcProcessor; + this.rpcErrorsCounter = + metricsSystem.createLabelledCounter( + BesuMetricCategory.RPC, + "errors_count", + "Number of errors per RPC method and RPC error type", + "rpcMethod", + "errorType"); } @Override @@ -41,6 +54,7 @@ public JsonRpcResponse process( JsonRpcResponse jsonRpcResponse = rpcProcessor.process(id, method, metricSpan, request); if (JsonRpcResponseType.ERROR == jsonRpcResponse.getType()) { JsonRpcErrorResponse errorResponse = (JsonRpcErrorResponse) jsonRpcResponse; + this.rpcErrorsCounter.labels(method.getName(), errorResponse.getErrorType().name()).inc(); switch (errorResponse.getErrorType()) { case INVALID_PARAMS: metricSpan.setStatus(StatusCode.ERROR, "Invalid Params"); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java index 989041547a6..c645bab453f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java @@ -119,6 +119,7 @@ private JsonRpcErrorResponse errorResponse( } else { final TransactionProcessingResult resultTrx = result.result(); if (resultTrx != null && resultTrx.getRevertReason().isPresent()) { + return errorResponse( request, new JsonRpcError(