You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuweni.apache.org by to...@apache.org on 2021/07/23 20:54:40 UTC

[incubator-tuweni] branch main updated: Add metering handler

This is an automated email from the ASF dual-hosted git repository.

toulmean pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-tuweni.git


The following commit(s) were added to refs/heads/main by this push:
     new 4842d54  Add metering handler
     new 5fd5759  Merge pull request #313 from atoulme/add_metering_handler
4842d54 is described below

commit 4842d545e7100a6ac6a0ed66d0d536baa21209cc
Author: Antoine Toulme <an...@lunar-ocean.com>
AuthorDate: Fri Jul 23 13:02:58 2021 -0700

    Add metering handler
---
 jsonrpc/build.gradle                               |  3 ++
 .../tuweni/jsonrpc/methods/MethodsHandler.kt       | 17 +++++-
 .../tuweni/jsonrpc/methods/MethodsHandlerTest.kt   | 61 ++++++++++++++++++++++
 3 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/jsonrpc/build.gradle b/jsonrpc/build.gradle
index f23b45f..af246fc 100644
--- a/jsonrpc/build.gradle
+++ b/jsonrpc/build.gradle
@@ -17,6 +17,8 @@ dependencies {
   implementation 'com.fasterxml.jackson.core:jackson-databind'
   implementation "com.google.guava:guava"
   implementation "org.jetbrains.kotlin:kotlin-stdlib"
+  implementation 'io.opentelemetry:opentelemetry-api-metrics'
+  implementation 'io.opentelemetry:opentelemetry-sdk-metrics'
   implementation 'io.vertx:vertx-core'
   implementation 'io.vertx:vertx-web-client'
   implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core'
@@ -32,6 +34,7 @@ dependencies {
   testImplementation 'org.bouncycastle:bcprov-jdk15on'
   testImplementation 'org.junit.jupiter:junit-jupiter-api'
   testImplementation 'org.junit.jupiter:junit-jupiter-params'
+  testImplementation 'io.opentelemetry:opentelemetry-sdk'
 
   testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
 
diff --git a/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandler.kt b/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandler.kt
index c9b419c..0f9e5c6 100644
--- a/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandler.kt
+++ b/jsonrpc/src/main/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandler.kt
@@ -16,6 +16,8 @@
  */
 package org.apache.tuweni.jsonrpc.methods
 
+import io.opentelemetry.api.metrics.LongCounter
+import io.opentelemetry.api.metrics.common.Labels
 import org.apache.tuweni.eth.JSONRPCRequest
 import org.apache.tuweni.eth.JSONRPCResponse
 import org.apache.tuweni.eth.methodNotFound
@@ -32,7 +34,20 @@ class MethodsRouter(val methodsMap: Map<String, (JSONRPCRequest) -> JSONRPCRespo
   }
 }
 
+class MeteredHandler(private val successCounter: LongCounter, private val failCounter: LongCounter, private val delegateHandler: (JSONRPCRequest) -> JSONRPCResponse) {
+
+  fun handleRequest(request: JSONRPCRequest): JSONRPCResponse {
+    val resp = delegateHandler(request)
+    val labels = Labels.of("method", request.method)
+    if (resp.error != null) {
+      failCounter.add(1, labels)
+    } else {
+      successCounter.add(1, labels)
+    }
+    return resp
+  }
+}
+
 // TODO DelegateHandler - choose from a number of handlers to see which to delegate to.
-// TODO MeteredHandler - count number of responses, error responses
 // TODO FilterHandler - filter incoming requests per allowlist
 // TODO CachingHandler - cache some incoming requests
diff --git a/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandlerTest.kt b/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandlerTest.kt
index eede7ea..82fd680 100644
--- a/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandlerTest.kt
+++ b/jsonrpc/src/test/kotlin/org/apache/tuweni/jsonrpc/methods/MethodsHandlerTest.kt
@@ -16,6 +16,10 @@
  */
 package org.apache.tuweni.jsonrpc.methods
 
+import io.opentelemetry.sdk.metrics.SdkMeterProvider
+import io.opentelemetry.sdk.metrics.export.IntervalMetricReader
+import io.opentelemetry.sdk.metrics.export.MetricProducer
+import io.opentelemetry.sdk.metrics.testing.InMemoryMetricExporter
 import org.apache.tuweni.eth.JSONRPCRequest
 import org.apache.tuweni.eth.JSONRPCResponse
 import org.apache.tuweni.eth.methodNotFound
@@ -23,6 +27,7 @@ import org.apache.tuweni.junit.BouncyCastleExtension
 import org.junit.jupiter.api.Assertions.assertEquals
 import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith
+import java.util.Collections
 
 @ExtendWith(BouncyCastleExtension::class)
 class MethodsHandlerTest {
@@ -38,4 +43,60 @@ class MethodsHandlerTest {
     val methodsRouter = MethodsRouter(mapOf(Pair("web3_sha3", ::sha3)))
     assertEquals(JSONRPCResponse(1, result = "0xd4fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1"), methodsRouter.handleRequest(JSONRPCRequest(1, "web3_sha3", arrayOf("0xdeadbeef"))))
   }
+
+  @Test
+  fun testCountSuccess() {
+    val exporter = InMemoryMetricExporter.create()
+    val meterSdk = SdkMeterProvider.builder().build()
+    val meter = meterSdk.get("handler")
+    val intervalMetricReader =
+      IntervalMetricReader.builder()
+        .setMetricExporter(exporter)
+        .setMetricProducers(Collections.singletonList(meterSdk) as Collection<MetricProducer>)
+        .setExportIntervalMillis(1000)
+        .build()
+    intervalMetricReader.start()
+    val successCounter = meter.longCounterBuilder("success").build()
+    val failCounter = meter.longCounterBuilder("fail").build()
+    val meteredHandler = MeteredHandler(successCounter, failCounter) {
+      JSONRPCResponse(1)
+    }
+    meteredHandler.handleRequest(JSONRPCRequest(1, "foo", emptyArray()))
+    Thread.sleep(1200)
+    var metricValue = 0L
+    for (metric in exporter.finishedMetricItems) {
+      if (metric.name == "success") {
+        metricValue = metric.longSumData.points.first().value
+      }
+    }
+    assertEquals(1L, metricValue)
+  }
+
+  @Test
+  fun testFailMeter() {
+    val exporter = InMemoryMetricExporter.create()
+    val meterSdk = SdkMeterProvider.builder().build()
+    val meter = meterSdk.get("handler")
+    val intervalMetricReader =
+      IntervalMetricReader.builder()
+        .setMetricExporter(exporter)
+        .setMetricProducers(Collections.singletonList(meterSdk) as Collection<MetricProducer>)
+        .setExportIntervalMillis(1000)
+        .build()
+    intervalMetricReader.start()
+    val successCounter = meter.longCounterBuilder("success").build()
+    val failCounter = meter.longCounterBuilder("fail").build()
+    val meteredHandler = MeteredHandler(successCounter, failCounter) {
+      JSONRPCResponse(1, error = "foo")
+    }
+    meteredHandler.handleRequest(JSONRPCRequest(1, "foo", emptyArray()))
+    Thread.sleep(1200)
+    var metricValue = 0L
+    for (metric in exporter.finishedMetricItems) {
+      if (metric.name == "fail") {
+        metricValue = metric.longSumData.points.first().value
+      }
+    }
+    assertEquals(1L, metricValue)
+  }
 }

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tuweni.apache.org
For additional commands, e-mail: commits-help@tuweni.apache.org