From 734a2fdaa6fc48081926849ffe8579c6c481cfeb Mon Sep 17 00:00:00 2001 From: Bradley Bown Date: Mon, 20 Jan 2025 09:19:20 +0000 Subject: [PATCH] Extend MetricsFacade with createSimpleTimer() factory (#265) * Extend MetricsFacade with createSimpleTimer() factory * Rename Timer interface to TimerCapture * Use createSimpleTimer to create SimpleTimerCaptures throughout codebase * Fix test * Pass metrics facade * feat: add createDynamicTagTimer and update MetricsFacade codes * feat: update test cases in MicrometerMetricsFacadeTest * feat: update JsonRpcMessageProcessor to not for computing metrics parsing error * feat: add timer metric for calculating shnarf * feat: add metric for block compression ratio and blob utilization ratio * feat: revert back to internal val goNativeBlobCompressor * fix: spotless issue * fix: JsonRpcMessageProcessor constructor call * fix: VertxHttpJsonRpcClientFactory constructor call * feat: added the option for ratio metric in createHistogram * feat: remove no-daemon option in transaction-exclusion-api build * feat: revised metrics handling in JsonRpcMessageProcessor * feat: changed tag value on error * feat: return error cases in handleMessage as succeededFuture instead of failedFuture * fix: use MicrometerMetricsFacade in VertxHttpJsonRpcClientFactory --------- Co-authored-by: jonesho --- ...action-exclusion-api-build-and-publish.yml | 2 +- .../zkevm/coordinator/app/CoordinatorApp.kt | 7 +- .../zkevm/coordinator/app/L1DependentApp.kt | 10 +- .../coordinator/clients/ShomeiClientTest.kt | 6 +- .../TracesGeneratorJsonRpcClientV1Test.kt | 5 +- .../TracesGeneratorJsonRpcClientV2Test.kt | 5 +- coordinator/core/build.gradle | 1 + .../blob/BlobCompressionProofCoordinator.kt | 14 +- .../coordination/blob/BlobCompressor.kt | 49 +++++- .../coordination/blob/BlobShnarfCalulator.kt | 38 ++-- .../conflation/ConflationServiceImpl.kt | 6 +- .../blob/GoBackedBlobCompressorTest.kt | 11 +- .../GoBackedCalculateShnarfCalculatorTest.kt | 7 +- .../net/consensys/zkevm/domain/BlobRecord.kt | 9 +- .../gas-pricing/static-cap/build.gradle | 1 + ...ineableFeesPricerServiceIntegrationTest.kt | 5 +- .../staticcap/ExtraDataV1UpdaterImplTest.kt | 6 +- .../staticcap/GasPriceUpdaterImplTest.kt | 6 +- .../dao/blob/BlobsPostgresDaoTest.kt | 2 - jvm-libs/generic/json-rpc/build.gradle | 1 + .../linea/jsonrpc/JsonRpcMessageProcessor.kt | 164 ++++++++++-------- .../jsonrpc/client/VertxHttpJsonRpcClient.kt | 22 +-- .../client/VertxHttpJsonRpcClientFactory.kt | 6 +- .../linea/jsonrpc/TestingJsonRpcServerTest.kt | 3 +- .../jsonrpc/JsonRpcMessageProcessorTest.kt | 12 +- .../jsonrpc/client/JsonRpcV2ClientImplTest.kt | 5 +- .../client/VertxHttpJsonRpcClientTest.kt | 10 +- .../linea/jsonrpc/TestingJsonRpcServer.kt | 3 +- .../clients/linea-state-manager/build.gradle | 1 + .../StateManagerV1JsonRpcClientTest.kt | 5 +- .../consensys/linea/metrics/MetricsFacade.kt | 37 +++- .../micrometer/AbstractTimerCapture.kt | 2 +- .../micrometer/DynamicTagTimerCapture.kt | 32 ++-- .../micrometer/MicrometerMetricsFacade.kt | 76 ++++++-- .../metrics/micrometer/SimpleTimerCapture.kt | 7 +- .../micrometer/MicrometerMetricsFacadeTest.kt | 129 ++++++++++++++ state-recover/besu-plugin/build.gradle | 1 + .../staterecover/plugin/AppConfigurator.kt | 3 +- .../build.gradle | 3 + .../el/ExecutionLayerJsonRpcClientTest.kt | 5 +- state-recover/test-cases/build.gradle | 1 + .../staterecover/StateRecoverAppIntTest.kt | 6 +- ...ecoverAppWithFakeExecutionClientIntTest.kt | 6 +- ...RecoveryManualReplayToLocalStackIntTest.kt | 6 +- ...erSepoliaWithFakeExecutionClientIntTest.kt | 6 +- traces-api-facade/app/build.gradle | 1 + .../linea/traces/app/TracesApiFacadeApp.kt | 13 +- .../net/consensys/linea/traces/app/api/Api.kt | 6 +- .../app/TransactionExclusionApp.kt | 2 +- .../linea/transactionexclusion/app/api/Api.kt | 6 +- .../TransactionExclusionServiceV1Impl.kt | 6 +- 51 files changed, 578 insertions(+), 198 deletions(-) diff --git a/.github/workflows/transaction-exclusion-api-build-and-publish.yml b/.github/workflows/transaction-exclusion-api-build-and-publish.yml index fb09686b1..e5102d21f 100644 --- a/.github/workflows/transaction-exclusion-api-build-and-publish.yml +++ b/.github/workflows/transaction-exclusion-api-build-and-publish.yml @@ -76,7 +76,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Build dist run: | - ./gradlew transaction-exclusion-api:app:installDist --no-daemon + ./gradlew transaction-exclusion-api:app:installDist - name: Login to Docker Hub if: ${{ env.DOCKERHUB_USERNAME != '' && env.DOCKERHUB_TOKEN != '' }} uses: docker/login-action@v3 diff --git a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorApp.kt b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorApp.kt index 1b1f75b69..1b7c8e7ec 100644 --- a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorApp.kt +++ b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/CoordinatorApp.kt @@ -47,9 +47,10 @@ class CoordinatorApp(private val configs: CoordinatorConfig) { Vertx.vertx(vertxConfig) } private val meterRegistry: MeterRegistry = BackendRegistries.getDefaultNow() + private val micrometerMetricsFacade = MicrometerMetricsFacade(meterRegistry, "linea") private val httpJsonRpcClientFactory = VertxHttpJsonRpcClientFactory( - vertx, - meterRegistry, + vertx = vertx, + metricsFacade = MicrometerMetricsFacade(meterRegistry), requestResponseLogLevel = Level.TRACE, failuresLogLevel = Level.WARN ) @@ -111,8 +112,6 @@ class CoordinatorApp(private val configs: CoordinatorConfig) { ) ) - private val micrometerMetricsFacade = MicrometerMetricsFacade(meterRegistry, "linea") - private val l1FeeHistoriesRepository = FeeHistoriesRepositoryImpl( FeeHistoriesRepositoryImpl.Config( diff --git a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt index 4b286a997..12da74314 100644 --- a/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt +++ b/coordinator/app/src/main/kotlin/net/consensys/zkevm/coordinator/app/L1DependentApp.kt @@ -380,7 +380,8 @@ class L1DependentApp( val compressorVersion = configs.traces.blobCompressorVersion val blobCompressor = GoBackedBlobCompressor.getInstance( compressorVersion = compressorVersion, - dataLimit = configs.blobCompression.blobSizeLimit.toUInt() + dataLimit = configs.blobCompression.blobSizeLimit.toUInt(), + metricsFacade = metricsFacade ) val compressedBlobCalculator = ConflationCalculatorByDataCompressed( @@ -475,7 +476,10 @@ class L1DependentApp( blobsRepository = blobsRepository, blobCompressionProverClient = proverClientFactory.blobCompressionProverClient(), rollingBlobShnarfCalculator = RollingBlobShnarfCalculator( - blobShnarfCalculator = GoBackedBlobShnarfCalculator(blobShnarfCalculatorVersion), + blobShnarfCalculator = GoBackedBlobShnarfCalculator( + version = blobShnarfCalculatorVersion, + metricsFacade = metricsFacade + ), blobsRepository = blobsRepository, genesisShnarf = genesisStateProvider.shnarf ), @@ -518,7 +522,7 @@ class L1DependentApp( private val alreadySubmittedBlobsFilter = L1ShnarfBasedAlreadySubmittedBlobsFilter( lineaRollup = lineaSmartContractClientForDataSubmission, - acceptedBlobEndBlockNumberConsumer = { highestAcceptedBlobTracker } + acceptedBlobEndBlockNumberConsumer = { highestAcceptedBlobTracker(it) } ) private val latestBlobSubmittedBlockNumberTracker = LatestBlobSubmittedBlockNumberTracker(0UL) diff --git a/coordinator/clients/shomei-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/ShomeiClientTest.kt b/coordinator/clients/shomei-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/ShomeiClientTest.kt index 86605e541..cf12d9e20 100644 --- a/coordinator/clients/shomei-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/ShomeiClientTest.kt +++ b/coordinator/clients/shomei-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/ShomeiClientTest.kt @@ -15,6 +15,8 @@ import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.async.get import net.consensys.linea.jsonrpc.client.JsonRpcClient import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import org.assertj.core.api.Assertions import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach @@ -35,9 +37,9 @@ class ShomeiClientTest { wiremock = WireMockServer(WireMockConfiguration.options().dynamicPort()) wiremock.start() meterRegistry = SimpleMeterRegistry() - + val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") + val rpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, metricsFacade) fakeShomeiServerURI = URI("http://127.0.0.1:" + wiremock.port()).toURL() - val rpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, meterRegistry) jsonRpcClient = rpcClientFactory.create(fakeShomeiServerURI) } diff --git a/coordinator/clients/traces-generator-api-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/TracesGeneratorJsonRpcClientV1Test.kt b/coordinator/clients/traces-generator-api-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/TracesGeneratorJsonRpcClientV1Test.kt index 2575af469..59642d21b 100644 --- a/coordinator/clients/traces-generator-api-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/TracesGeneratorJsonRpcClientV1Test.kt +++ b/coordinator/clients/traces-generator-api-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/TracesGeneratorJsonRpcClientV1Test.kt @@ -25,6 +25,8 @@ import net.consensys.linea.errors.ErrorResponse import net.consensys.linea.jsonrpc.client.JsonRpcClient import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.linea.traces.TracesCountersV1 import net.consensys.linea.traces.TracingModuleV1 import org.assertj.core.api.Assertions.assertThat @@ -71,7 +73,8 @@ class TracesGeneratorJsonRpcClientV1Test { fakeTracesServerUri = URI("http://127.0.0.1:" + wiremock.port()).toURL() meterRegistry = SimpleMeterRegistry() - val rpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, meterRegistry) + val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") + val rpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, metricsFacade) vertxHttpJsonRpcClient = rpcClientFactory.createWithRetries( fakeTracesServerUri, methodsToRetry = TracesGeneratorJsonRpcClientV1.retryableMethods, diff --git a/coordinator/clients/traces-generator-api-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/TracesGeneratorJsonRpcClientV2Test.kt b/coordinator/clients/traces-generator-api-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/TracesGeneratorJsonRpcClientV2Test.kt index 7ace0b62c..fe0a49e87 100644 --- a/coordinator/clients/traces-generator-api-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/TracesGeneratorJsonRpcClientV2Test.kt +++ b/coordinator/clients/traces-generator-api-client/src/test/kotlin/net/consensys/zkevm/coordinator/clients/TracesGeneratorJsonRpcClientV2Test.kt @@ -22,6 +22,8 @@ import net.consensys.linea.errors.ErrorResponse import net.consensys.linea.jsonrpc.client.JsonRpcClient import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.linea.traces.TracesCountersV2 import net.consensys.linea.traces.TracingModuleV2 import org.assertj.core.api.Assertions.assertThat @@ -66,7 +68,8 @@ class TracesGeneratorJsonRpcClientV2Test { fakeTracesServerUri = URI("http://127.0.0.1:" + wiremock.port()).toURL() meterRegistry = SimpleMeterRegistry() - val rpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, meterRegistry) + val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") + val rpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, metricsFacade) vertxHttpJsonRpcClient = rpcClientFactory.createWithRetries( fakeTracesServerUri, methodsToRetry = TracesGeneratorJsonRpcClientV2.retryableMethods, diff --git a/coordinator/core/build.gradle b/coordinator/core/build.gradle index 17b494707..d30859290 100644 --- a/coordinator/core/build.gradle +++ b/coordinator/core/build.gradle @@ -17,6 +17,7 @@ dependencies { api project(':jvm-libs:generic:extensions:futures') api "tech.pegasys.teku.internal:unsigned:${libs.versions.teku.get()}" api "org.jetbrains.kotlinx:kotlinx-datetime:${libs.versions.kotlinxDatetime.get()}" + implementation project(":jvm-libs:linea:metrics:micrometer") implementation "io.vertx:vertx-core" // jackson shall never be used in the core module // however, it is used already :( but was as transitive through Teku Execution Client diff --git a/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobCompressionProofCoordinator.kt b/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobCompressionProofCoordinator.kt index 20f6bea6a..74b77eca9 100644 --- a/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobCompressionProofCoordinator.kt +++ b/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobCompressionProofCoordinator.kt @@ -39,17 +39,17 @@ class BlobCompressionProofCoordinator( private var timerId: Long? = null private lateinit var blobPollingAction: Handler private val blobsCounter = metricsFacade.createCounter( - LineaMetricsCategory.BLOB, - "counter", - "New blobs arriving to blob compression proof coordinator" + category = LineaMetricsCategory.BLOB, + name = "counter", + description = "New blobs arriving to blob compression proof coordinator" ) init { metricsFacade.createGauge( - LineaMetricsCategory.BLOB, - "compression.queue.size", - "Size of blob compression proving queue", - { blobsToHandle.size } + category = LineaMetricsCategory.BLOB, + name = "compression.queue.size", + description = "Size of blob compression proving queue", + measurementSupplier = { blobsToHandle.size } ) } diff --git a/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobCompressor.kt b/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobCompressor.kt index 4f1a78a04..75c341177 100644 --- a/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobCompressor.kt +++ b/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobCompressor.kt @@ -4,6 +4,9 @@ import net.consensys.encodeHex import net.consensys.linea.blob.BlobCompressorVersion import net.consensys.linea.blob.GoNativeBlobCompressor import net.consensys.linea.blob.GoNativeBlobCompressorFactory +import net.consensys.linea.metrics.LineaMetricsCategory +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.TimerCapture import org.apache.logging.log4j.LogManager import kotlin.random.Random @@ -35,7 +38,9 @@ interface BlobCompressor { } class GoBackedBlobCompressor private constructor( - internal val goNativeBlobCompressor: GoNativeBlobCompressor + internal val goNativeBlobCompressor: GoNativeBlobCompressor, + private val dataLimit: UInt, + private val metricsFacade: MetricsFacade ) : BlobCompressor { companion object { @@ -44,7 +49,8 @@ class GoBackedBlobCompressor private constructor( fun getInstance( compressorVersion: BlobCompressorVersion = BlobCompressorVersion.V0_1_0, - dataLimit: UInt + dataLimit: UInt, + metricsFacade: MetricsFacade ): GoBackedBlobCompressor { if (instance == null) { synchronized(this) { @@ -57,7 +63,7 @@ class GoBackedBlobCompressor private constructor( if (!initialized) { throw InstantiationException(goNativeBlobCompressor.Error()) } - instance = GoBackedBlobCompressor(goNativeBlobCompressor) + instance = GoBackedBlobCompressor(goNativeBlobCompressor, dataLimit, metricsFacade) } else { throw IllegalStateException("Compressor singleton instance already created") } @@ -69,22 +75,52 @@ class GoBackedBlobCompressor private constructor( } } + private val canAppendBlockTimer: TimerCapture = metricsFacade.createSimpleTimer( + category = LineaMetricsCategory.BLOB, + name = "compressor.canappendblock", + description = "Time taken to check if block fits in current blob" + ) + private val appendBlockTimer: TimerCapture = metricsFacade.createSimpleTimer( + category = LineaMetricsCategory.BLOB, + name = "compressor.appendblock", + description = "Time taken to compress block into current blob" + ) + private val compressionRatioHistogram = metricsFacade.createHistogram( + category = LineaMetricsCategory.BLOB, + name = "block.compression.ratio", + description = "Block compression ratio measured in [0.0,1.0]", + isRatio = true + ) + private val utilizationRatioHistogram = metricsFacade.createHistogram( + category = LineaMetricsCategory.BLOB, + name = "data.utilization.ratio", + description = "Data utilization ratio of a blob measured in [0.0,1.0]", + isRatio = true + ) + private val log = LogManager.getLogger(GoBackedBlobCompressor::class.java) override fun canAppendBlock(blockRLPEncoded: ByteArray): Boolean { - return goNativeBlobCompressor.CanWrite(blockRLPEncoded, blockRLPEncoded.size) + return canAppendBlockTimer.captureTime { + goNativeBlobCompressor.CanWrite(blockRLPEncoded, blockRLPEncoded.size) + } } override fun appendBlock(blockRLPEncoded: ByteArray): BlobCompressor.AppendResult { val compressionSizeBefore = goNativeBlobCompressor.Len() - val appended = goNativeBlobCompressor.Write(blockRLPEncoded, blockRLPEncoded.size) + val appended = appendBlockTimer.captureTime { + goNativeBlobCompressor.Write(blockRLPEncoded, blockRLPEncoded.size) + } val compressedSizeAfter = goNativeBlobCompressor.Len() + val compressionRatio = (1.0 - (compressedSizeAfter - compressionSizeBefore).toDouble() / blockRLPEncoded.size) + .also { compressionRatioHistogram.record(it) } + log.trace( "block compressed: blockRlpSize={} compressionDataBefore={} compressionDataAfter={} compressionRatio={}", blockRLPEncoded.size, compressionSizeBefore, compressedSizeAfter, - 1.0 - ((compressedSizeAfter - compressionSizeBefore).toDouble() / blockRLPEncoded.size) + compressionRatio ) val error = goNativeBlobCompressor.Error() if (error != null) { @@ -101,6 +137,7 @@ class GoBackedBlobCompressor private constructor( override fun getCompressedData(): ByteArray { val compressedData = ByteArray(goNativeBlobCompressor.Len()) goNativeBlobCompressor.Bytes(compressedData) + utilizationRatioHistogram.record(goNativeBlobCompressor.Len().toDouble() / dataLimit.toInt()) return compressedData } diff --git a/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobShnarfCalulator.kt b/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobShnarfCalulator.kt index 9350bea78..45566c20c 100644 --- a/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobShnarfCalulator.kt +++ b/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/blob/BlobShnarfCalulator.kt @@ -3,9 +3,13 @@ package net.consensys.zkevm.ethereum.coordination.blob import build.linea.domain.BlockIntervals import net.consensys.decodeHex import net.consensys.encodeHex +import net.consensys.linea.blob.CalculateShnarfResult import net.consensys.linea.blob.GoNativeBlobShnarfCalculator import net.consensys.linea.blob.GoNativeShnarfCalculatorFactory import net.consensys.linea.blob.ShnarfCalculatorVersion +import net.consensys.linea.metrics.LineaMetricsCategory +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.TimerCapture import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger import java.util.Base64 @@ -66,9 +70,17 @@ interface BlobShnarfCalculator { } class GoBackedBlobShnarfCalculator( - private val delegate: GoNativeBlobShnarfCalculator + private val delegate: GoNativeBlobShnarfCalculator, + private val metricsFacade: MetricsFacade ) : BlobShnarfCalculator { - constructor(version: ShnarfCalculatorVersion) : this(GoNativeShnarfCalculatorFactory.getInstance(version)) + constructor(version: ShnarfCalculatorVersion, metricsFacade: MetricsFacade) : + this(GoNativeShnarfCalculatorFactory.getInstance(version), metricsFacade) + + private val calculateShnarfTimer: TimerCapture = metricsFacade.createSimpleTimer( + category = LineaMetricsCategory.BLOB, + name = "shnarf.calculation", + description = "Time taken to calculate the shnarf hash of the given blob" + ) private val log: Logger = LogManager.getLogger(GoBackedBlobShnarfCalculator::class.java) @@ -97,16 +109,18 @@ class GoBackedBlobShnarfCalculator( conflationOrder ) - val result = delegate.CalculateShnarf( - eip4844Enabled = true, - compressedData = compressedDataB64, - parentStateRootHash = parentStateRootHash.encodeHex(), - finalStateRootHash = finalStateRootHash.encodeHex(), - prevShnarf = prevShnarf.encodeHex(), - conflationOrderStartingBlockNumber = conflationOrder.startingBlockNumber.toLong(), - conflationOrderUpperBoundariesLen = conflationOrder.upperBoundaries.size, - conflationOrderUpperBoundaries = conflationOrder.upperBoundaries.map { it.toLong() }.toLongArray() - ) + val result = calculateShnarfTimer.captureTime { + delegate.CalculateShnarf( + eip4844Enabled = true, + compressedData = compressedDataB64, + parentStateRootHash = parentStateRootHash.encodeHex(), + finalStateRootHash = finalStateRootHash.encodeHex(), + prevShnarf = prevShnarf.encodeHex(), + conflationOrderStartingBlockNumber = conflationOrder.startingBlockNumber.toLong(), + conflationOrderUpperBoundariesLen = conflationOrder.upperBoundaries.size, + conflationOrderUpperBoundaries = conflationOrder.upperBoundaries.map { it.toLong() }.toLongArray() + ) + } if (result.errorMessage.isNotEmpty()) { val errorMessage = "Error while calculating Shnarf. error=${result.errorMessage}" diff --git a/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/conflation/ConflationServiceImpl.kt b/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/conflation/ConflationServiceImpl.kt index 80fa89628..22cd4c5ff 100644 --- a/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/conflation/ConflationServiceImpl.kt +++ b/coordinator/core/src/main/kotlin/net/consensys/zkevm/ethereum/coordination/conflation/ConflationServiceImpl.kt @@ -33,9 +33,9 @@ class ConflationServiceImpl( internal val blocksToConflate = PriorityBlockingQueue() private val blocksCounter = metricsFacade.createCounter( - LineaMetricsCategory.CONFLATION, - "blocks.imported", - "New blocks arriving to conflation service counter" + category = LineaMetricsCategory.CONFLATION, + name = "blocks.imported", + description = "New blocks arriving to conflation service counter" ) init { diff --git a/coordinator/core/src/test/kotlin/net/consensys/zkevm/coordination/blob/GoBackedBlobCompressorTest.kt b/coordinator/core/src/test/kotlin/net/consensys/zkevm/coordination/blob/GoBackedBlobCompressorTest.kt index cd43d26b4..75a839cdd 100644 --- a/coordinator/core/src/test/kotlin/net/consensys/zkevm/coordination/blob/GoBackedBlobCompressorTest.kt +++ b/coordinator/core/src/test/kotlin/net/consensys/zkevm/coordination/blob/GoBackedBlobCompressorTest.kt @@ -1,6 +1,9 @@ package net.consensys.zkevm.coordination.blob +import io.micrometer.core.instrument.simple.SimpleMeterRegistry import net.consensys.linea.blob.BlobCompressorVersion +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.zkevm.ethereum.coordination.blob.BlobCompressionException import net.consensys.zkevm.ethereum.coordination.blob.GoBackedBlobCompressor import org.assertj.core.api.Assertions.assertThat @@ -17,7 +20,13 @@ class GoBackedBlobCompressorTest { companion object { private const val DATA_LIMIT = 16 * 1024 private val TEST_DATA = loadTestData() - private val compressor = GoBackedBlobCompressor.getInstance(BlobCompressorVersion.V0_1_0, DATA_LIMIT.toUInt()) + private val meterRegistry = SimpleMeterRegistry() + private val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") + private val compressor = GoBackedBlobCompressor.getInstance( + BlobCompressorVersion.V0_1_0, + DATA_LIMIT.toUInt(), + metricsFacade + ) private fun loadTestData(): Array { val data = GoBackedBlobCompressorTest::class.java.getResourceAsStream("rlp_blocks.bin")!!.readAllBytes() diff --git a/coordinator/core/src/test/kotlin/net/consensys/zkevm/coordination/blob/GoBackedCalculateShnarfCalculatorTest.kt b/coordinator/core/src/test/kotlin/net/consensys/zkevm/coordination/blob/GoBackedCalculateShnarfCalculatorTest.kt index b1db17fc0..7e0b2fdab 100644 --- a/coordinator/core/src/test/kotlin/net/consensys/zkevm/coordination/blob/GoBackedCalculateShnarfCalculatorTest.kt +++ b/coordinator/core/src/test/kotlin/net/consensys/zkevm/coordination/blob/GoBackedCalculateShnarfCalculatorTest.kt @@ -1,10 +1,13 @@ package net.consensys.zkevm.coordination.blob import build.linea.domain.BlockIntervals +import io.micrometer.core.instrument.simple.SimpleMeterRegistry import net.consensys.decodeHex import net.consensys.encodeHex import net.consensys.linea.blob.CalculateShnarfResult import net.consensys.linea.blob.GoNativeBlobShnarfCalculator +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.zkevm.ethereum.coordination.blob.GoBackedBlobShnarfCalculator import net.consensys.zkevm.ethereum.coordination.blob.ShnarfResult import org.apache.tuweni.bytes.Bytes32 @@ -22,6 +25,8 @@ import org.mockito.kotlin.whenever class GoBackedCalculateShnarfCalculatorTest { private lateinit var delegate: GoNativeBlobShnarfCalculator private lateinit var calculator: GoBackedBlobShnarfCalculator + private val meterRegistry = SimpleMeterRegistry() + private val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") private val compressedData = byteArrayOf(0b01001101, 0b01100001, 0b01101110) private val compressedDataBase64String = "TWFu" private val parentStateRootHash = Bytes32.random().toArray() @@ -52,7 +57,7 @@ class GoBackedCalculateShnarfCalculatorTest { @BeforeEach fun beforeEach() { delegate = mock() - calculator = GoBackedBlobShnarfCalculator(delegate) + calculator = GoBackedBlobShnarfCalculator(delegate, metricsFacade) } @Test diff --git a/coordinator/core/src/testFixtures/kotlin/net/consensys/zkevm/domain/BlobRecord.kt b/coordinator/core/src/testFixtures/kotlin/net/consensys/zkevm/domain/BlobRecord.kt index aafc7bb31..71b692bd2 100644 --- a/coordinator/core/src/testFixtures/kotlin/net/consensys/zkevm/domain/BlobRecord.kt +++ b/coordinator/core/src/testFixtures/kotlin/net/consensys/zkevm/domain/BlobRecord.kt @@ -1,9 +1,12 @@ package net.consensys.zkevm.domain import build.linea.domain.BlockIntervals +import io.micrometer.core.instrument.simple.SimpleMeterRegistry import kotlinx.datetime.Clock import kotlinx.datetime.Instant import net.consensys.linea.blob.ShnarfCalculatorVersion +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.setFirstByteToZero import net.consensys.trimToSecondPrecision import net.consensys.zkevm.coordinator.clients.BlobCompressionProof @@ -12,7 +15,11 @@ import net.consensys.zkevm.ethereum.coordination.blob.BlobShnarfCalculator import net.consensys.zkevm.ethereum.coordination.blob.GoBackedBlobShnarfCalculator import kotlin.random.Random -private val shnarfCalculator: BlobShnarfCalculator = GoBackedBlobShnarfCalculator(ShnarfCalculatorVersion.V0_1_0) +private val meterRegistry = SimpleMeterRegistry() +private val metricsFacade: MetricsFacade = + MicrometerMetricsFacade(registry = meterRegistry, metricsPrefix = "linea") +private val shnarfCalculator: BlobShnarfCalculator = + GoBackedBlobShnarfCalculator(version = ShnarfCalculatorVersion.V0_1_0, metricsFacade = metricsFacade) fun createBlobRecord( startBlockNumber: ULong? = null, diff --git a/coordinator/ethereum/gas-pricing/static-cap/build.gradle b/coordinator/ethereum/gas-pricing/static-cap/build.gradle index 59ec63d5f..7d8c00081 100644 --- a/coordinator/ethereum/gas-pricing/static-cap/build.gradle +++ b/coordinator/ethereum/gas-pricing/static-cap/build.gradle @@ -13,6 +13,7 @@ dependencies { testImplementation("io.vertx:vertx-junit5") testImplementation "com.github.tomakehurst:wiremock-jre8:${libs.versions.wiremock.get()}" + testImplementation project(':jvm-libs:linea:metrics:micrometer') testImplementation project(':coordinator:clients:smart-contract-client') } diff --git a/coordinator/ethereum/gas-pricing/static-cap/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/coordination/dynamicgasprice/MinMineableFeesPricerServiceIntegrationTest.kt b/coordinator/ethereum/gas-pricing/static-cap/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/coordination/dynamicgasprice/MinMineableFeesPricerServiceIntegrationTest.kt index 0ce64043c..1ff8f831d 100644 --- a/coordinator/ethereum/gas-pricing/static-cap/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/coordination/dynamicgasprice/MinMineableFeesPricerServiceIntegrationTest.kt +++ b/coordinator/ethereum/gas-pricing/static-cap/src/integrationTest/kotlin/net/consensys/zkevm/ethereum/coordination/dynamicgasprice/MinMineableFeesPricerServiceIntegrationTest.kt @@ -16,6 +16,8 @@ import net.consensys.linea.ethereum.gaspricing.staticcap.GasUsageRatioWeightedAv import net.consensys.linea.ethereum.gaspricing.staticcap.MinMineableFeesPricerService import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.linea.web3j.Web3jBlobExtended import net.consensys.toHexString import net.consensys.toULong @@ -53,6 +55,7 @@ import kotlin.time.Duration.Companion.seconds @Disabled("Disable this test for now as causes issues with other tests because of price updates") class MinMineableFeesPricerServiceIntegrationTest { private val meterRegistry = SimpleMeterRegistry() + private val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") private val pollingInterval = 2.seconds private val feeHistoryBlockCount = 10u private val feeHistoryRewardPercentile = 15.0 @@ -362,7 +365,7 @@ class MinMineableFeesPricerServiceIntegrationTest { } private fun createGasPriceUpdater(vertx: Vertx) = GasPriceUpdaterImpl( - VertxHttpJsonRpcClientFactory(vertx, meterRegistry), + VertxHttpJsonRpcClientFactory(vertx, metricsFacade), GasPriceUpdaterImpl.Config( gethEndpoints = gethRecipients.map { URI(it).toURL() }, besuEndPoints = besuRecipients.map { URI(it).toURL() }, diff --git a/coordinator/ethereum/gas-pricing/static-cap/src/test/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/ExtraDataV1UpdaterImplTest.kt b/coordinator/ethereum/gas-pricing/static-cap/src/test/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/ExtraDataV1UpdaterImplTest.kt index 62343949b..bec460028 100644 --- a/coordinator/ethereum/gas-pricing/static-cap/src/test/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/ExtraDataV1UpdaterImplTest.kt +++ b/coordinator/ethereum/gas-pricing/static-cap/src/test/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/ExtraDataV1UpdaterImplTest.kt @@ -17,6 +17,8 @@ import io.vertx.junit5.VertxTestContext import net.consensys.linea.ethereum.gaspricing.MinerExtraDataV1 import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -64,7 +66,9 @@ class ExtraDataV1UpdaterImplTest { wiremock = WireMockServer(wireMockConfig().dynamicPort()) wiremock.start() sequencerEndpoint = URI("http://localhost:${wiremock.port()}/sequencer/").toURL() - jsonRpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, SimpleMeterRegistry()) + val meterRegistry = SimpleMeterRegistry() + val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") + jsonRpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, metricsFacade) } @AfterEach diff --git a/coordinator/ethereum/gas-pricing/static-cap/src/test/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/GasPriceUpdaterImplTest.kt b/coordinator/ethereum/gas-pricing/static-cap/src/test/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/GasPriceUpdaterImplTest.kt index 183aff0c0..6b697f803 100644 --- a/coordinator/ethereum/gas-pricing/static-cap/src/test/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/GasPriceUpdaterImplTest.kt +++ b/coordinator/ethereum/gas-pricing/static-cap/src/test/kotlin/net/consensys/linea/ethereum/gaspricing/staticcap/GasPriceUpdaterImplTest.kt @@ -14,6 +14,8 @@ import io.vertx.junit5.VertxExtension import io.vertx.junit5.VertxTestContext import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import org.assertj.core.api.Assertions import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach @@ -72,9 +74,11 @@ class GasPriceUpdaterImplTest { URI("http://localhost:${wiremock.port()}/besu-2/").toURL(), URI("http://localhost:${wiremock.port()}/besu-3/").toURL() ) + val meterRegistry = SimpleMeterRegistry() + val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") jsonRpcClientFactory = VertxHttpJsonRpcClientFactory( vertx, - SimpleMeterRegistry() + metricsFacade ) } diff --git a/coordinator/persistence/blob/src/integrationTest/kotlin/net/consensys/zkevm/persistence/dao/blob/BlobsPostgresDaoTest.kt b/coordinator/persistence/blob/src/integrationTest/kotlin/net/consensys/zkevm/persistence/dao/blob/BlobsPostgresDaoTest.kt index 194305b2e..28a6eeb84 100644 --- a/coordinator/persistence/blob/src/integrationTest/kotlin/net/consensys/zkevm/persistence/dao/blob/BlobsPostgresDaoTest.kt +++ b/coordinator/persistence/blob/src/integrationTest/kotlin/net/consensys/zkevm/persistence/dao/blob/BlobsPostgresDaoTest.kt @@ -23,7 +23,6 @@ import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith import tech.pegasys.teku.infrastructure.async.SafeFuture import java.util.concurrent.ExecutionException -import kotlin.random.Random import kotlin.time.Duration.Companion.seconds import kotlin.time.toJavaDuration @@ -45,7 +44,6 @@ class BlobsPostgresDaoTest : CleanDbTestSuiteParallel() { private val expectedEndBlock = 100UL private val expectedStartBlockTime = fakeClock.now().trimToSecondPrecision() private val expectedEndBlockTime = fakeClock.now().plus(1200.seconds).trimToMillisecondPrecision() - private val expectedShnarf = Random.nextBytes(32) @BeforeEach fun beforeEach() { diff --git a/jvm-libs/generic/json-rpc/build.gradle b/jvm-libs/generic/json-rpc/build.gradle index f52a677f3..0c0dc1bc2 100644 --- a/jvm-libs/generic/json-rpc/build.gradle +++ b/jvm-libs/generic/json-rpc/build.gradle @@ -7,6 +7,7 @@ plugins { description = "JSON RPC 2.0 utilities" dependencies { + implementation project(":jvm-libs:linea:core:metrics") implementation project(":jvm-libs:linea:metrics:micrometer") implementation project(":jvm-libs:generic:extensions:futures") implementation project(":jvm-libs:generic:extensions:kotlin") diff --git a/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/JsonRpcMessageProcessor.kt b/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/JsonRpcMessageProcessor.kt index 2b3c65b7b..c05bff953 100644 --- a/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/JsonRpcMessageProcessor.kt +++ b/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/JsonRpcMessageProcessor.kt @@ -11,10 +11,6 @@ import com.github.michaelbull.result.map import com.github.michaelbull.result.merge import com.github.michaelbull.result.recover import com.github.michaelbull.result.unwrap -import io.micrometer.core.instrument.Clock -import io.micrometer.core.instrument.Counter -import io.micrometer.core.instrument.MeterRegistry -import io.micrometer.core.instrument.Timer import io.vertx.core.AsyncResult import io.vertx.core.CompositeFuture import io.vertx.core.Future @@ -26,8 +22,8 @@ import io.vertx.core.json.JsonObject import io.vertx.core.json.jackson.DatabindCodec import io.vertx.core.json.jackson.VertxModule import io.vertx.ext.auth.User -import net.consensys.linea.metrics.micrometer.DynamicTagTimerCapture -import net.consensys.linea.metrics.micrometer.SimpleTimerCapture +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.Tag import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger @@ -54,7 +50,7 @@ private data class RequestContext( */ class JsonRpcMessageProcessor( private val requestsHandler: JsonRpcRequestHandler, - private val meterRegistry: MeterRegistry, + private val metricsFacade: MetricsFacade, private val requestParser: JsonRpcRequestParser = Companion::parseRequest, private val log: Logger = LogManager.getLogger(JsonRpcMessageProcessor::class.java), private val responseResultObjectMapper: ObjectMapper = jacksonObjectMapper().registerModules(VertxModule()), @@ -64,44 +60,83 @@ class JsonRpcMessageProcessor( DatabindCodec.mapper().registerKotlinModule() } - private val counterBuilder = Counter.builder("jsonrpc.counter") override fun invoke(user: User?, messageJsonStr: String): Future = - handleMessage(user, messageJsonStr) + handleAndMeasureRequestProcessing(user, messageJsonStr) - private fun handleMessage(user: User?, requestJsonStr: String): Future { - val wholeRequestTimer = - Timer.builder("jsonrpc.processing.whole") - .description( - "Processing of JSON-RPC message: Deserialization + Business Logic + Serialization" + private fun handleAndMeasureRequestProcessing( + user: User?, + requestJsonStr: String + ): Future { + return Future.fromCompletionStage( + metricsFacade.createDynamicTagTimer>( + name = "jsonrpc.processing.whole", + description = "Processing of JSON-RPC message: Deserialization + Business Logic + Serialization", + tagKey = "method", + tagValueExtractorOnError = { "METHOD_PROCESSING_ERROR" } + ) { + it.first!! + } + .captureTime( + handleMessage( + user = user, + requestJsonStr = requestJsonStr + ).toCompletionStage().toCompletableFuture() ) - val timerSample = Timer.start(Clock.SYSTEM) + .thenApply { + logResponse(it.third, it.second, requestJsonStr) + it.second + } + ) + } + + private fun handleMessage(user: User?, requestJsonStr: String): Future> { val json: Any = when (val result = decodeMessage(requestJsonStr)) { is Ok -> result.value is Err -> { - return Future.succeededFuture(Json.encode(result.error)) + return Future.succeededFuture(Triple(null, Json.encode(result.error), false)) } } log.trace(json) val isBulkRequest: Boolean = json is JsonArray val jsonArray = if (isBulkRequest) json as JsonArray else JsonArray().add(json) - val parsingResults: List, JsonRpcErrorResponse>> = + val requestParsingResults: List, JsonRpcErrorResponse>> = jsonArray.map(::measureRequestParsing) // all or nothing: if any of the requests has a parsing error, return before execution - parsingResults.forEach { + requestParsingResults.forEach { when (it) { - is Err -> return Future.succeededFuture(Json.encode(it.error)) + is Err -> return Future.succeededFuture(Triple(null, Json.encode(it.error), false)) is Ok -> Unit } } + val methodTag = + if (isBulkRequest) { + "bulk_request" + } else { + requestParsingResults.first() + .unwrap().first.method + } + + return handleMessageRequests( + user = user, + parsingResults = requestParsingResults, + methodTag = methodTag + ) + } + + private fun handleMessageRequests( + user: User?, + parsingResults: List, JsonRpcErrorResponse>>, + methodTag: String + ): Future> { var allSuccessful = true val executionFutures: List> = parsingResults.map { result -> // all success results at this state val (rpc: JsonRpcRequest, jsonObj: JsonObject) = result.unwrap() - handleRequest(user, rpc, jsonObj) + handleAndMeasureRequestHandling(user, rpc, jsonObj) .map { RequestContext(rpc.id, rpc.method, it) } .recover { error: Throwable -> log.error( @@ -133,80 +168,71 @@ class JsonRpcMessageProcessor( return Future.all(serializedResponses) .transform { ar: AsyncResult -> - val methodTag = - if (isBulkRequest) { - "bulk_request" - } else { - parsingResults.first() - .unwrap().first.method - } - wholeRequestTimer.tag("method", methodTag) - val responses = ar.result().list() val finalResponseJsonStr = if (responses.size == 1) { responses.first() } else { - SimpleTimerCapture( - meterRegistry, - "jsonrpc.serialization.response.bulk" - ) - .setDescription("Time of bulk json response serialization") - .captureTime { responses.joinToString(",", "[", "]") } + metricsFacade.createSimpleTimer( + name = "jsonrpc.serialization.response.bulk", + description = "Time of bulk json response serialization" + ).captureTime { responses.joinToString(",", "[", "]") } } - - timerSample.stop(wholeRequestTimer.register(meterRegistry)) - logResponse(allSuccessful, finalResponseJsonStr, requestJsonStr) - Future.succeededFuture(finalResponseJsonStr) + Future.succeededFuture(Triple(methodTag, finalResponseJsonStr, allSuccessful)) } } private fun measureRequestParsing( json: Any ): Result, JsonRpcErrorResponse> { - return DynamicTagTimerCapture, JsonRpcErrorResponse>>( - meterRegistry, - "jsonrpc.serialization.request" - ) - .setTagKey("method") - .setDescription("json-rpc method parsing") - .setTagValueExtractor { parsingResult: Result, JsonRpcErrorResponse> -> - parsingResult.map { it.first.method }.recover { "METHOD_PARSE_ERROR" }.value - } - .setTagValueExtractorOnError { "METHOD_PARSE_ERROR" } - .captureTime { requestParser(json) } + return metricsFacade.createDynamicTagTimer( + name = "jsonrpc.serialization.request", + description = "json-rpc method parsing", + tagKey = "method", + tagValueExtractorOnError = { "METHOD_PARSE_ERROR" } + ) { + parsingResult: Result, JsonRpcErrorResponse> -> + parsingResult.map { it.first.method }.recover { "METHOD_PARSE_ERROR" }.value + }.captureTime { requestParser(json) } } private fun encodeAndMeasureResponse(requestContext: RequestContext): String { - return SimpleTimerCapture(meterRegistry, "jsonrpc.serialization.response") - .setDescription("Time of json response serialization") - .setTag("method", requestContext.method) - .captureTime { - val result = requestContext.result.map { successResponse -> - val resultJsonNode = responseResultObjectMapper.valueToTree(successResponse.result) - successResponse.copy(result = resultJsonNode) - } - rpcEnvelopeObjectMapper.writeValueAsString(result.merge()) + val timerCapture = metricsFacade.createSimpleTimer( + name = "jsonrpc.serialization.response", + description = "Time of json response serialization", + tags = listOf(Tag("method", requestContext.method)) + ) + + return timerCapture.captureTime { + val result = requestContext.result.map { successResponse -> + val resultJsonNode = responseResultObjectMapper.valueToTree(successResponse.result) + successResponse.copy(result = resultJsonNode) } + rpcEnvelopeObjectMapper.writeValueAsString(result.merge()) + } } - private fun handleRequest( + private fun handleAndMeasureRequestHandling( user: User?, jsonRpcRequest: JsonRpcRequest, requestJson: JsonObject ): Future> { - return SimpleTimerCapture>( - meterRegistry, - "jsonrpc.processing.logic" + return metricsFacade.createSimpleTimer>>( + name = "jsonrpc.processing.logic", + description = "Processing of a particular JRPC method's logic without SerDes", + tags = listOf(Tag("method", jsonRpcRequest.method)) ) - .setTag("method", jsonRpcRequest.method) - .setDescription("Processing of a particular JRPC method's logic without SerDes") - .captureTime(callRequestHandlerAndCatchError(user, jsonRpcRequest, requestJson)) + .captureTime { callRequestHandlerAndCatchError(user, jsonRpcRequest, requestJson) } .onComplete { result: AsyncResult> -> val success = (result.succeeded() && result.result() is Ok) - counterBuilder.tag("success", success.toString()) - counterBuilder.tag("method", jsonRpcRequest.method) - counterBuilder.register(meterRegistry).increment() + metricsFacade.createCounter( + name = "jsonrpc.counter", + description = "Counting the JSON rpc request with result and method", + tags = listOf( + Tag("success", success.toString()), + Tag("method", jsonRpcRequest.method) + ) + ).increment() } } diff --git a/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClient.kt b/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClient.kt index 42eb78843..a4463b8ea 100644 --- a/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClient.kt +++ b/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClient.kt @@ -6,7 +6,6 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.github.michaelbull.result.Err import com.github.michaelbull.result.Ok import com.github.michaelbull.result.Result -import io.micrometer.core.instrument.MeterRegistry import io.vertx.core.Future import io.vertx.core.buffer.Buffer import io.vertx.core.http.HttpClient @@ -19,7 +18,8 @@ import net.consensys.linea.jsonrpc.JsonRpcErrorResponse import net.consensys.linea.jsonrpc.JsonRpcRequest import net.consensys.linea.jsonrpc.JsonRpcRequestData import net.consensys.linea.jsonrpc.JsonRpcSuccessResponse -import net.consensys.linea.metrics.micrometer.SimpleTimerCapture +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.Tag import org.apache.logging.log4j.Level import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger @@ -29,7 +29,7 @@ import java.net.URL class VertxHttpJsonRpcClient( private val httpClient: HttpClient, private val endpoint: URL, - private val meterRegistry: MeterRegistry, + private val metricsFacade: MetricsFacade, private val requestParamsObjectMapper: ObjectMapper = objectMapper, private val responseObjectMapper: ObjectMapper = objectMapper, private val log: Logger = LogManager.getLogger(VertxHttpJsonRpcClient::class.java), @@ -85,14 +85,16 @@ class VertxHttpJsonRpcClient( } } - SimpleTimerCapture>( - meterRegistry, - "jsonrpc.request" + Future.fromCompletionStage( + metricsFacade.createSimpleTimer>( + name = "jsonrpc.request", + description = "Time of Upstream API JsonRpc Requests", + tags = listOf( + Tag("endpoint", endpoint.host), + Tag("method", request.method) + ) + ).captureTime(requestFuture.toCompletionStage().toCompletableFuture()) ) - .setDescription("Time of Upstream API JsonRpc Requests") - .setTag("endpoint", endpoint.host) - .setTag("method", request.method) - .captureTime(requestFuture) } .onFailure { th -> logRequestFailure(json, th) } } diff --git a/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClientFactory.kt b/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClientFactory.kt index 577174cc1..2bd694715 100644 --- a/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClientFactory.kt +++ b/jvm-libs/generic/json-rpc/src/main/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClientFactory.kt @@ -3,10 +3,10 @@ package net.consensys.linea.jsonrpc.client import com.fasterxml.jackson.databind.ObjectMapper import com.github.michaelbull.result.Err import com.github.michaelbull.result.Result -import io.micrometer.core.instrument.MeterRegistry import io.vertx.core.Vertx import io.vertx.core.http.HttpClientOptions import io.vertx.core.http.HttpVersion +import net.consensys.linea.metrics.MetricsFacade import org.apache.logging.log4j.Level import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger @@ -36,7 +36,7 @@ interface JsonRpcClientFactory { class VertxHttpJsonRpcClientFactory( private val vertx: Vertx, - private val meterRegistry: MeterRegistry, + private val metricsFacade: MetricsFacade, private val requestResponseLogLevel: Level = Level.TRACE, private val failuresLogLevel: Level = Level.DEBUG, private val requestIdSupplier: Supplier = SequentialIdSupplier.singleton @@ -62,7 +62,7 @@ class VertxHttpJsonRpcClientFactory( return VertxHttpJsonRpcClient( httpClient, endpoint, - meterRegistry, + metricsFacade, log = log, requestParamsObjectMapper = requestObjectMapper, responseObjectMapper = responseObjectMapper, diff --git a/jvm-libs/generic/json-rpc/src/test/kotlin/linea/jsonrpc/TestingJsonRpcServerTest.kt b/jvm-libs/generic/json-rpc/src/test/kotlin/linea/jsonrpc/TestingJsonRpcServerTest.kt index efe0c552c..bc3ba6215 100644 --- a/jvm-libs/generic/json-rpc/src/test/kotlin/linea/jsonrpc/TestingJsonRpcServerTest.kt +++ b/jvm-libs/generic/json-rpc/src/test/kotlin/linea/jsonrpc/TestingJsonRpcServerTest.kt @@ -11,6 +11,7 @@ import net.consensys.linea.jsonrpc.JsonRpcSuccessResponse import net.consensys.linea.jsonrpc.client.JsonRpcV2Client import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy import org.junit.jupiter.api.BeforeEach @@ -33,7 +34,7 @@ class TestingJsonRpcServerTest { ) val rpcClientFactory = VertxHttpJsonRpcClientFactory( vertx = vertx, - meterRegistry = SimpleMeterRegistry() + metricsFacade = MicrometerMetricsFacade(registry = SimpleMeterRegistry()) ) client = rpcClientFactory.createJsonRpcV2Client( endpoints = listOf(URI.create("http://localhost:${jsonRpcServer.boundPort}")), diff --git a/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/JsonRpcMessageProcessorTest.kt b/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/JsonRpcMessageProcessorTest.kt index 4bec02f53..5d0dbee50 100644 --- a/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/JsonRpcMessageProcessorTest.kt +++ b/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/JsonRpcMessageProcessorTest.kt @@ -10,6 +10,8 @@ import io.vertx.core.json.JsonObject import io.vertx.ext.auth.User import io.vertx.junit5.VertxExtension import io.vertx.junit5.VertxTestContext +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -21,6 +23,7 @@ private fun Future.get() = this.toCompletionStage().toCompletableFuture() class JsonRpcMessageProcessorTest { private lateinit var processor: JsonRpcMessageProcessor private lateinit var meterRegistry: SimpleMeterRegistry + private lateinit var metricsFacade: MetricsFacade @BeforeEach fun setUp() { @@ -29,7 +32,8 @@ class JsonRpcMessageProcessorTest { Future.succeededFuture(Ok(JsonRpcSuccessResponse(jsonRpcRequest.id, JsonObject()))) } meterRegistry = SimpleMeterRegistry() - processor = JsonRpcMessageProcessor(fakeRequestHandlerAlwaysSuccess, meterRegistry) + metricsFacade = MicrometerMetricsFacade(registry = meterRegistry) + processor = JsonRpcMessageProcessor(fakeRequestHandlerAlwaysSuccess, metricsFacade) } @Test @@ -39,7 +43,7 @@ class JsonRpcMessageProcessorTest { val request = buildJsonRpcRequest(method = "eth_blockNumber") val processor = JsonRpcMessageProcessor( { _, _, _ -> throw RuntimeException("Something went wrong") }, - meterRegistry + metricsFacade ) processor(null, request.toString()) .onComplete( @@ -182,7 +186,7 @@ class JsonRpcMessageProcessorTest { val jsonStr = Json.encode(JsonArray(requests)) - processor = JsonRpcMessageProcessor(fakeRequestHandlerWithSomeFailures, meterRegistry) + processor = JsonRpcMessageProcessor(fakeRequestHandlerWithSomeFailures, metricsFacade) processor(null, jsonStr) .onComplete( @@ -232,7 +236,7 @@ class JsonRpcMessageProcessorTest { ) val singleAsBulk = listOf(buildJsonRpcRequest(id = 10, "read_value")) - processor = JsonRpcMessageProcessor(fakeRequestHandlerWithSomeFailures, meterRegistry) + processor = JsonRpcMessageProcessor(fakeRequestHandlerWithSomeFailures, metricsFacade) processor(null, Json.encode(request1)).get() processor(null, Json.encode(request2)).get() processor(null, Json.encode(request3)).get() diff --git a/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/client/JsonRpcV2ClientImplTest.kt b/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/client/JsonRpcV2ClientImplTest.kt index cc9afa145..409c501cb 100644 --- a/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/client/JsonRpcV2ClientImplTest.kt +++ b/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/client/JsonRpcV2ClientImplTest.kt @@ -26,6 +26,8 @@ import io.vertx.core.json.JsonObject import io.vertx.junit5.VertxExtension import net.consensys.decodeHex import net.consensys.linea.jsonrpc.JsonRpcErrorResponseException +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy @@ -97,7 +99,8 @@ class JsonRpcV2ClientImplTest { fun beforeEach(vertx: Vertx) { this.vertx = vertx this.meterRegistry = SimpleMeterRegistry() - this.factory = VertxHttpJsonRpcClientFactory(vertx, meterRegistry) + val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") + this.factory = VertxHttpJsonRpcClientFactory(vertx, metricsFacade) this.client = createClientAndSetupWireMockServer() } diff --git a/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClientTest.kt b/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClientTest.kt index 2bbbf5154..9750f7f72 100644 --- a/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClientTest.kt +++ b/jvm-libs/generic/json-rpc/src/test/kotlin/net/consensys/linea/jsonrpc/client/VertxHttpJsonRpcClientTest.kt @@ -25,6 +25,8 @@ import net.consensys.linea.jsonrpc.JsonRpcError import net.consensys.linea.jsonrpc.JsonRpcErrorResponse import net.consensys.linea.jsonrpc.JsonRpcRequestListParams import net.consensys.linea.jsonrpc.JsonRpcSuccessResponse +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import org.apache.logging.log4j.Level import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger @@ -49,6 +51,7 @@ class VertxHttpJsonRpcClientTest { private lateinit var wiremock: WireMockServer private val path = "/api/v1?appKey=1234" private lateinit var meterRegistry: SimpleMeterRegistry + private lateinit var metricsFacade: MetricsFacade private val clientOptions = HttpClientOptions() .setKeepAlive(true) @@ -63,7 +66,8 @@ class VertxHttpJsonRpcClientTest { wiremock.start() endpoint = URI(wiremock.baseUrl() + path).toURL() meterRegistry = SimpleMeterRegistry() - client = VertxHttpJsonRpcClient(vertx.createHttpClient(clientOptions), endpoint, meterRegistry) + metricsFacade = MicrometerMetricsFacade(registry = meterRegistry) + client = VertxHttpJsonRpcClient(vertx.createHttpClient(clientOptions), endpoint, metricsFacade) } @AfterEach @@ -294,7 +298,7 @@ class VertxHttpJsonRpcClientTest { client = VertxHttpJsonRpcClient( vertx.createHttpClient(clientOptions), endpoint, - meterRegistry, + metricsFacade, log = log ) @@ -322,7 +326,7 @@ class VertxHttpJsonRpcClientTest { client = VertxHttpJsonRpcClient( vertx.createHttpClient(clientOptions), endpoint, - meterRegistry, + metricsFacade, log = log ) diff --git a/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt b/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt index 44e9591b2..642b64309 100644 --- a/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt +++ b/jvm-libs/generic/json-rpc/src/testFixtures/kotlin/linea/jsonrpc/TestingJsonRpcServer.kt @@ -20,6 +20,7 @@ import net.consensys.linea.jsonrpc.JsonRpcMessageProcessor import net.consensys.linea.jsonrpc.JsonRpcRequest import net.consensys.linea.jsonrpc.JsonRpcSuccessResponse import net.consensys.linea.jsonrpc.httpserver.HttpJsonRpcServer +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.Logger import tech.pegasys.teku.infrastructure.async.SafeFuture @@ -60,7 +61,7 @@ open class TestingJsonRpcServer( requestHandler = HttpRequestHandler( JsonRpcMessageProcessor( requestsHandler = this::handleRequest, - meterRegistry = SimpleMeterRegistry(), + metricsFacade = MicrometerMetricsFacade(registry = SimpleMeterRegistry()), log = log, responseResultObjectMapper = responseObjectMapper ) diff --git a/jvm-libs/linea/clients/linea-state-manager/build.gradle b/jvm-libs/linea/clients/linea-state-manager/build.gradle index f74f4ff52..246e90cea 100644 --- a/jvm-libs/linea/clients/linea-state-manager/build.gradle +++ b/jvm-libs/linea/clients/linea-state-manager/build.gradle @@ -19,6 +19,7 @@ dependencies { implementation "com.fasterxml.jackson.module:jackson-module-kotlin:${libs.versions.jackson.get()}" testImplementation(project(":jvm-libs:linea:testing:file-system")) + testImplementation project(':jvm-libs:linea:metrics:micrometer') testImplementation "io.vertx:vertx-junit5" testImplementation "com.github.tomakehurst:wiremock-jre8:${libs.versions.wiremock.get()}" } diff --git a/jvm-libs/linea/clients/linea-state-manager/src/test/kotlin/build/linea/clients/StateManagerV1JsonRpcClientTest.kt b/jvm-libs/linea/clients/linea-state-manager/src/test/kotlin/build/linea/clients/StateManagerV1JsonRpcClientTest.kt index e47fff9ab..6735ccd0c 100644 --- a/jvm-libs/linea/clients/linea-state-manager/src/test/kotlin/build/linea/clients/StateManagerV1JsonRpcClientTest.kt +++ b/jvm-libs/linea/clients/linea-state-manager/src/test/kotlin/build/linea/clients/StateManagerV1JsonRpcClientTest.kt @@ -19,6 +19,8 @@ import net.consensys.linea.async.get import net.consensys.linea.errors.ErrorResponse import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.linea.testing.filesystem.findPathTo import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy @@ -54,8 +56,9 @@ class StateManagerV1JsonRpcClientTest { wiremock = WireMockServer(options().dynamicPort()) wiremock.start() meterRegistry = SimpleMeterRegistry() + val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") stateManagerClient = StateManagerV1JsonRpcClient.create( - rpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, meterRegistry), + rpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, metricsFacade), endpoints = listOf(URI(wiremock.baseUrl())), maxInflightRequestsPerClient = 1u, requestRetry = RequestRetryConfig( diff --git a/jvm-libs/linea/core/metrics/src/main/kotlin/net/consensys/linea/metrics/MetricsFacade.kt b/jvm-libs/linea/core/metrics/src/main/kotlin/net/consensys/linea/metrics/MetricsFacade.kt index 0226bbe68..7de07a9c2 100644 --- a/jvm-libs/linea/core/metrics/src/main/kotlin/net/consensys/linea/metrics/MetricsFacade.kt +++ b/jvm-libs/linea/core/metrics/src/main/kotlin/net/consensys/linea/metrics/MetricsFacade.kt @@ -1,14 +1,17 @@ package net.consensys.linea.metrics +import java.util.concurrent.Callable +import java.util.concurrent.CompletableFuture +import java.util.function.Function import java.util.function.Supplier data class Tag(val key: String, val value: String) enum class LineaMetricsCategory { - CONFLATION, + AGGREGATION, BATCH, BLOB, - AGGREGATION, + CONFLATION, GAS_PRICE_CAP, TX_EXCLUSION_API; @@ -27,9 +30,14 @@ interface Histogram { fun record(data: Double) } +interface TimerCapture { + fun captureTime(f: CompletableFuture): CompletableFuture + fun captureTime(action: Callable): T +} + interface MetricsFacade { fun createGauge( - category: LineaMetricsCategory, + category: LineaMetricsCategory? = null, name: String, description: String, measurementSupplier: Supplier, @@ -37,17 +45,34 @@ interface MetricsFacade { ) fun createCounter( - category: LineaMetricsCategory, + category: LineaMetricsCategory? = null, name: String, description: String, tags: List = emptyList() ): Counter fun createHistogram( - category: LineaMetricsCategory, + category: LineaMetricsCategory? = null, name: String, description: String, tags: List = emptyList(), - baseUnit: String + isRatio: Boolean = false, + baseUnit: String? = null ): Histogram + + fun createSimpleTimer( + category: LineaMetricsCategory? = null, + name: String, + description: String, + tags: List = emptyList() + ): TimerCapture + + fun createDynamicTagTimer( + category: LineaMetricsCategory? = null, + name: String, + description: String, + tagKey: String, + tagValueExtractorOnError: Function, + tagValueExtractor: Function + ): TimerCapture } diff --git a/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/AbstractTimerCapture.kt b/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/AbstractTimerCapture.kt index a951d18bb..6c1c1128b 100644 --- a/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/AbstractTimerCapture.kt +++ b/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/AbstractTimerCapture.kt @@ -44,7 +44,7 @@ abstract class AbstractTimerCapture { return this } - abstract fun captureTime(f: Callable): T + abstract fun captureTime(action: Callable): T abstract fun captureTime(f: CompletableFuture): CompletableFuture open fun captureTime(f: SafeFuture): SafeFuture { captureTime(f.toCompletableFuture()) diff --git a/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/DynamicTagTimerCapture.kt b/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/DynamicTagTimerCapture.kt index fd3c1e1d9..3a352a283 100644 --- a/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/DynamicTagTimerCapture.kt +++ b/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/DynamicTagTimerCapture.kt @@ -3,6 +3,7 @@ package net.consensys.linea.metrics.micrometer import io.micrometer.core.instrument.Clock import io.micrometer.core.instrument.MeterRegistry import io.micrometer.core.instrument.Timer +import net.consensys.linea.metrics.TimerCapture import java.util.concurrent.Callable import java.util.concurrent.CompletableFuture import java.util.function.Function @@ -14,41 +15,46 @@ import java.util.function.Function * nanosecond-level measurements. Related issue: * https://github.com/micrometer-metrics/micrometer/issues/535 */ -class DynamicTagTimerCapture(meterRegistry: MeterRegistry, name: String) : - AbstractTimerCapture(meterRegistry, name) { - private var extractor: Function? = null +class DynamicTagTimerCapture : AbstractTimerCapture, TimerCapture { + private var extractor: Function? = null private var extractorOnError: Function? = null private var tagKey: String? = null - override fun setDescription(description: String): DynamicTagTimerCapture { + constructor(meterRegistry: MeterRegistry, name: String) : super(meterRegistry, name) + constructor( + meterRegistry: MeterRegistry, + timerBuilder: Timer.Builder + ) : super(meterRegistry, timerBuilder) + + override fun setDescription(description: String): DynamicTagTimerCapture { super.setDescription(description) return this } - override fun setTag(tagKey: String, tagValue: String): DynamicTagTimerCapture { + override fun setTag(tagKey: String, tagValue: String): DynamicTagTimerCapture { throw NoSuchMethodException( "If you need to set both value and key, please use ${SimpleTimerCapture::class.qualifiedName}" ) } - override fun setClock(clock: Clock): DynamicTagTimerCapture { + override fun setClock(clock: Clock): DynamicTagTimerCapture { super.setClock(clock) return this } - fun setTagKey(tagKey: String?): DynamicTagTimerCapture { + fun setTagKey(tagKey: String?): DynamicTagTimerCapture { this.tagKey = tagKey return this } - fun setTagValueExtractor(extractor: Function): DynamicTagTimerCapture { + fun setTagValueExtractor(extractor: Function): DynamicTagTimerCapture { this.extractor = extractor return this } fun setTagValueExtractorOnError( onErrorExtractor: Function - ): DynamicTagTimerCapture { + ): DynamicTagTimerCapture { this.extractorOnError = onErrorExtractor return this } @@ -59,10 +65,10 @@ class DynamicTagTimerCapture(meterRegistry: MeterRegistry, name: String) : assert(tagKey != null) } - override fun captureTime(f: CompletableFuture): CompletableFuture { + override fun captureTime(f: CompletableFuture): CompletableFuture { ensureValidState() val timerSample = Timer.start(clock) - f.whenComplete { result: Out?, error: Throwable? -> + f.whenComplete { result: T?, error: Throwable? -> val tagValue: String = result?.let(extractor!!::apply) ?: extractorOnError!!.apply(error!!) val timer = timerBuilder.tag(tagKey!!, tagValue).register(meterRegistry) timerSample.stop(timer) @@ -70,10 +76,10 @@ class DynamicTagTimerCapture(meterRegistry: MeterRegistry, name: String) : return f } - override fun captureTime(f: Callable): Out { + override fun captureTime(action: Callable): T { ensureValidState() val timerSample = Timer.start(clock) - val result = f.call() + val result = action.call() val labelValue = extractor!!.apply(result) val timer = timerBuilder.tag(tagKey!!, labelValue).register(meterRegistry) timerSample.stop(timer) diff --git a/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/MicrometerMetricsFacade.kt b/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/MicrometerMetricsFacade.kt index 09ea32dff..d2d5abd7e 100644 --- a/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/MicrometerMetricsFacade.kt +++ b/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/MicrometerMetricsFacade.kt @@ -8,10 +8,16 @@ import net.consensys.linea.metrics.Histogram import net.consensys.linea.metrics.LineaMetricsCategory import net.consensys.linea.metrics.MetricsFacade import net.consensys.linea.metrics.Tag +import net.consensys.linea.metrics.TimerCapture +import java.util.function.Function import java.util.function.Supplier import io.micrometer.core.instrument.Counter as MicrometerCounter +import io.micrometer.core.instrument.Timer as MicrometerTimer -class MicrometerMetricsFacade(private val registry: MeterRegistry, private val metricsPrefix: String) : MetricsFacade { +class MicrometerMetricsFacade( + private val registry: MeterRegistry, + private val metricsPrefix: String? = null +) : MetricsFacade { companion object { private val validBaseUnits = listOf( "seconds", @@ -30,17 +36,23 @@ class MicrometerMetricsFacade(private val registry: MeterRegistry, private val m } init { - requireValidMicrometerName(metricsPrefix) + if (metricsPrefix != null) requireValidMicrometerName(metricsPrefix) + } + + private fun metricHandle(category: LineaMetricsCategory?, metricName: String): String { + val prefixName = if (metricsPrefix == null) "" else "$metricsPrefix." + val categoryName = if (category == null) "" else "$category." + return "$prefixName$categoryName$metricName" } override fun createGauge( - category: LineaMetricsCategory, + category: LineaMetricsCategory?, name: String, description: String, measurementSupplier: Supplier, tags: List ) { - requireValidMicrometerName(category.toString()) + if (category != null) requireValidMicrometerName(category.toString()) requireValidMicrometerName(name) val builder = Gauge.builder(metricHandle(category, name), measurementSupplier) if (tags.isNotEmpty()) { @@ -55,12 +67,12 @@ class MicrometerMetricsFacade(private val registry: MeterRegistry, private val m } override fun createCounter( - category: LineaMetricsCategory, + category: LineaMetricsCategory?, name: String, description: String, tags: List ): Counter { - requireValidMicrometerName(category.toString()) + if (category != null) requireValidMicrometerName(category.toString()) requireValidMicrometerName(name) val builder = MicrometerCounter.builder(metricHandle(category, name)) if (tags.isNotEmpty()) { @@ -75,15 +87,16 @@ class MicrometerMetricsFacade(private val registry: MeterRegistry, private val m } override fun createHistogram( - category: LineaMetricsCategory, + category: LineaMetricsCategory?, name: String, description: String, tags: List, - baseUnit: String + isRatio: Boolean, + baseUnit: String? ): Histogram { - requireValidMicrometerName(category.toString()) + if (category != null) requireValidMicrometerName(category.toString()) requireValidMicrometerName(name) - requireValidBaseUnit(baseUnit) + if (baseUnit != null) requireValidBaseUnit(baseUnit) val distributionSummaryBuilder = DistributionSummary.builder(metricHandle(category, name)) if (tags.isNotEmpty()) { val flatTags = tags.flatMap { @@ -94,10 +107,49 @@ class MicrometerMetricsFacade(private val registry: MeterRegistry, private val m } distributionSummaryBuilder.description(description) distributionSummaryBuilder.baseUnit(baseUnit) + if (isRatio) { + distributionSummaryBuilder.scale(100.0) + distributionSummaryBuilder.maximumExpectedValue(100.0) + } return MicrometerHistogramAdapter(distributionSummaryBuilder.register(registry)) } - private fun metricHandle(category: LineaMetricsCategory, metricName: String): String { - return "$metricsPrefix.$category.$metricName" + override fun createSimpleTimer( + category: LineaMetricsCategory?, + name: String, + description: String, + tags: List + ): TimerCapture { + if (category != null) requireValidMicrometerName(category.toString()) + requireValidMicrometerName(name) + val builder = MicrometerTimer.builder(metricHandle(category, name)) + if (tags.isNotEmpty()) { + val flatTags = tags.flatMap { + requireValidMicrometerName(it.key) + listOf(it.key, it.value) + } + builder.tags(*flatTags.toTypedArray()) + } + builder.description(description) + + return SimpleTimerCapture(registry, builder) + } + + override fun createDynamicTagTimer( + category: LineaMetricsCategory?, + name: String, + description: String, + tagKey: String, + tagValueExtractorOnError: Function, + tagValueExtractor: Function + ): TimerCapture { + if (category != null) requireValidMicrometerName(category.toString()) + requireValidMicrometerName(name) + requireValidMicrometerName(tagKey) + return DynamicTagTimerCapture(registry, metricHandle(category, name)) + .setDescription(description) + .setTagKey(tagKey) + .setTagValueExtractor(tagValueExtractor) + .setTagValueExtractorOnError(tagValueExtractorOnError) } } diff --git a/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/SimpleTimerCapture.kt b/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/SimpleTimerCapture.kt index 92fd3a3d1..416c6a5ef 100644 --- a/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/SimpleTimerCapture.kt +++ b/jvm-libs/linea/metrics/micrometer/src/main/kotlin/net/consensys/linea/metrics/micrometer/SimpleTimerCapture.kt @@ -3,6 +3,7 @@ package net.consensys.linea.metrics.micrometer import io.micrometer.core.instrument.Clock import io.micrometer.core.instrument.MeterRegistry import io.micrometer.core.instrument.Timer +import net.consensys.linea.metrics.TimerCapture import java.util.concurrent.Callable import java.util.concurrent.CompletableFuture @@ -12,7 +13,7 @@ import java.util.concurrent.CompletableFuture * captures TODO: In order to improve performance, Timer instances can be cached into a thread safe * Map */ -class SimpleTimerCapture : AbstractTimerCapture { +class SimpleTimerCapture : AbstractTimerCapture, TimerCapture { constructor(meterRegistry: MeterRegistry, name: String) : super(meterRegistry, name) constructor( meterRegistry: MeterRegistry, @@ -41,10 +42,10 @@ class SimpleTimerCapture : AbstractTimerCapture { return f } - override fun captureTime(f: Callable): T { + override fun captureTime(action: Callable): T { val timer = timerBuilder.register(meterRegistry) val timerSample = Timer.start(clock) - val result = f.call() + val result = action.call() timerSample.stop(timer) return result } diff --git a/jvm-libs/linea/metrics/micrometer/src/test/kotlin/net/consensys/linea/metrics/micrometer/MicrometerMetricsFacadeTest.kt b/jvm-libs/linea/metrics/micrometer/src/test/kotlin/net/consensys/linea/metrics/micrometer/MicrometerMetricsFacadeTest.kt index 248e155de..39df4fcb3 100644 --- a/jvm-libs/linea/metrics/micrometer/src/test/kotlin/net/consensys/linea/metrics/micrometer/MicrometerMetricsFacadeTest.kt +++ b/jvm-libs/linea/metrics/micrometer/src/test/kotlin/net/consensys/linea/metrics/micrometer/MicrometerMetricsFacadeTest.kt @@ -10,6 +10,7 @@ import org.assertj.core.api.Assertions.assertThat import org.assertj.core.data.Offset import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import java.util.concurrent.TimeUnit class MicrometerMetricsFacadeTest { private lateinit var meterRegistry: MeterRegistry @@ -81,6 +82,9 @@ class MicrometerMetricsFacadeTest { val createdHistogram = meterRegistry.find("linea.test.batch.some.metric").summary() assertThat(createdHistogram).isNotNull assertThat(createdHistogram!!.id.description).isEqualTo("This is a test metric") + assertThat(createdHistogram.id.tags).isEqualTo( + listOf(ImmutableTag("key1", "value1"), ImmutableTag("key2", "value2")) + ) assertThat(createdHistogram.id.baseUnit).isEqualTo("seconds") assertThat(createdHistogram.count()).isEqualTo(0L) @@ -100,4 +104,129 @@ class MicrometerMetricsFacadeTest { assertThat(createdHistogram.mean()).isCloseTo(38.333, Offset.offset(0.1)) assertThat(createdHistogram.max()).isEqualTo(100.0) } + + @Test + fun `createSimpleTimer creates timer with specified parameters`() { + fun mockTimer() { + Thread.sleep(200L) + } + + val expectedTags = listOf(Tag("key1", "value1"), Tag("key2", "value2")) + val timer = metricsFacade.createSimpleTimer( + name = "some.timer.metric", + description = "This is a test metric", + tags = expectedTags + ) + + timer.captureTime(::mockTimer) + val createdTimer = meterRegistry.find("linea.test.some.timer.metric").timer() + assertThat(createdTimer).isNotNull + assertThat(createdTimer!!.id.description).isEqualTo("This is a test metric") + assertThat(createdTimer.id.tags).isEqualTo(listOf(ImmutableTag("key1", "value1"), ImmutableTag("key2", "value2"))) + assertThat(createdTimer.max(TimeUnit.SECONDS)).isGreaterThan(0.2) + + timer.captureTime(::mockTimer) + assertThat(createdTimer.totalTime(TimeUnit.SECONDS)).isGreaterThan(0.4) + assertThat(createdTimer.mean(TimeUnit.SECONDS)).isGreaterThan(0.2) + } + + @Test + fun `createDynamicTagTimer creates timer with specified parameters`() { + fun mockTimer() { + Thread.sleep(200L) + } + + val timer = metricsFacade.createDynamicTagTimer( + name = "some.dynamictag.timer.metric", + description = "This is a test metric", + tagKey = "key", + tagValueExtractorOnError = { "unfound_key" } + ) { + "value" + } + + timer.captureTime(::mockTimer) + val createdTimer = meterRegistry.find("linea.test.some.dynamictag.timer.metric").timer() + assertThat(createdTimer).isNotNull + assertThat(createdTimer!!.id.description).isEqualTo("This is a test metric") + assertThat(createdTimer.id.tags).isEqualTo(listOf(ImmutableTag("key", "value"))) + assertThat(createdTimer.max(TimeUnit.SECONDS)).isGreaterThan(0.2) + + timer.captureTime(::mockTimer) + assertThat(createdTimer.totalTime(TimeUnit.SECONDS)).isGreaterThan(0.4) + assertThat(createdTimer.mean(TimeUnit.SECONDS)).isGreaterThan(0.2) + } + + @Test + fun `createGauge creates gauge with correct name when metrics prefix and category are absent`() { + val metricMeasureValue = 0L + val meterRegistry = SimpleMeterRegistry() + val metricsFacade = MicrometerMetricsFacade(meterRegistry) + metricsFacade.createGauge( + name = "some.gauge.metric", + description = "This is a test metric", + measurementSupplier = { metricMeasureValue }, + tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")) + ) + val createdGauge = meterRegistry.find("some.gauge.metric").gauge() + assertThat(createdGauge).isNotNull + } + + @Test + fun `createCounter creates counter with correct name when metrics prefix and category are absent`() { + val meterRegistry = SimpleMeterRegistry() + val metricsFacade = MicrometerMetricsFacade(meterRegistry) + metricsFacade.createCounter( + name = "some.counter.metric", + description = "This is a test metric", + tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")) + ) + val createdCounter = meterRegistry.find("some.counter.metric").counter() + assertThat(createdCounter).isNotNull + } + + @Test + fun `createHistogram creates histogram with correct name when metrics prefix and category are absent`() { + val meterRegistry = SimpleMeterRegistry() + val metricsFacade = MicrometerMetricsFacade(meterRegistry) + metricsFacade.createHistogram( + name = "some.histogram.metric", + description = "This is a test metric", + tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")), + baseUnit = "seconds" + ) + val createdHistogram = meterRegistry.find("some.histogram.metric").summary() + assertThat(createdHistogram).isNotNull + } + + @Test + fun `createSimpleTimer creates timer with correct name when metrics prefix and category are absent`() { + val meterRegistry = SimpleMeterRegistry() + val metricsFacade = MicrometerMetricsFacade(meterRegistry) + val timer = metricsFacade.createSimpleTimer( + name = "some.timer.metric", + description = "This is a test metric", + tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")) + ) + timer.captureTime {} + val createdTimer = meterRegistry.find("some.timer.metric").timer() + assertThat(createdTimer).isNotNull + } + + @Test + fun `createDynamicTagTimer creates timer with correct name when metrics prefix and category are absent`() { + val meterRegistry = SimpleMeterRegistry() + val metricsFacade = MicrometerMetricsFacade(meterRegistry) + val timer = metricsFacade.createDynamicTagTimer( + name = "some.dynamictag.timer.metric", + description = "This is a test metric", + tagKey = "key", + tagValueExtractorOnError = { "unfound_key" } + ) { + "value" + } + timer.captureTime {} + val createdTimer = meterRegistry.find("some.dynamictag.timer.metric").timer() + assertThat(createdTimer).isNotNull + } } diff --git a/state-recover/besu-plugin/build.gradle b/state-recover/besu-plugin/build.gradle index b8a9c92f2..1b7c385a7 100644 --- a/state-recover/besu-plugin/build.gradle +++ b/state-recover/besu-plugin/build.gradle @@ -12,6 +12,7 @@ dependencies { because 'Required for command line parsing. Provided by Besu at runtime.' } implementation "org.jetbrains.kotlin:kotlin-reflect:1.9.21" + api(project(":jvm-libs:linea:metrics:micrometer")) api(project(":jvm-libs:generic:serialization:jackson")) api(project(":jvm-libs:linea:clients:linea-l1-contract-client")) api(project(":jvm-libs:linea:web3j-extensions")) diff --git a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt index e7b25bec2..f86262914 100644 --- a/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt +++ b/state-recover/besu-plugin/src/main/kotlin/linea/staterecover/plugin/AppConfigurator.kt @@ -16,6 +16,7 @@ import linea.web3j.Web3JLogsSearcher import linea.web3j.createWeb3jHttpClient import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import org.apache.logging.log4j.LogManager import java.net.URI import kotlin.time.Duration.Companion.seconds @@ -56,7 +57,7 @@ fun createAppAllInProcess( ), logger = LogManager.getLogger("linea.plugin.staterecover.clients.l1.blob-scan") ) - val jsonRpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, meterRegistry) + val jsonRpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, MicrometerMetricsFacade(meterRegistry)) val stateManagerClient: StateManagerClientV1 = StateManagerV1JsonRpcClient.create( rpcClientFactory = jsonRpcClientFactory, endpoints = listOf(stateManagerClientEndpoint), diff --git a/state-recover/clients/execution-layer-json-rpc-client/build.gradle b/state-recover/clients/execution-layer-json-rpc-client/build.gradle index 70349a034..9a9752d09 100644 --- a/state-recover/clients/execution-layer-json-rpc-client/build.gradle +++ b/state-recover/clients/execution-layer-json-rpc-client/build.gradle @@ -13,6 +13,9 @@ dependencies { implementation(project(':state-recover:appcore:clients-interfaces')) implementation(project(':state-recover:appcore:domain-models')) + + testImplementation project(':jvm-libs:linea:core:metrics') + testImplementation project(':jvm-libs:linea:metrics:micrometer') testImplementation "com.github.tomakehurst:wiremock-jre8:${libs.versions.wiremock.get()}" testImplementation "net.javacrumbs.json-unit:json-unit-assertj:${libs.versions.jsonUnit.get()}" } diff --git a/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt b/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt index f59bd27c1..441e08881 100644 --- a/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt +++ b/state-recover/clients/execution-layer-json-rpc-client/src/test/kotlin/build/linea/staterecover/clients/el/ExecutionLayerJsonRpcClientTest.kt @@ -18,6 +18,8 @@ import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.BlockParameter import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.MetricsFacade +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.javacrumbs.jsonunit.assertj.assertThatJson import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.AfterEach @@ -40,8 +42,9 @@ class ExecutionLayerJsonRpcClientTest { wiremock.start() meterRegistry = SimpleMeterRegistry() + val metricsFacade: MetricsFacade = MicrometerMetricsFacade(registry = meterRegistry, "linea") client = ExecutionLayerJsonRpcClient.create( - rpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, meterRegistry), + rpcClientFactory = VertxHttpJsonRpcClientFactory(vertx, metricsFacade), endpoint = URI(wiremock.baseUrl()), requestRetryConfig = RequestRetryConfig( maxRetries = 3u, diff --git a/state-recover/test-cases/build.gradle b/state-recover/test-cases/build.gradle index 658a2cca5..69915cf0d 100644 --- a/state-recover/test-cases/build.gradle +++ b/state-recover/test-cases/build.gradle @@ -33,6 +33,7 @@ dependencies { implementation(project(":jvm-libs:linea:testing:l1-blob-and-proof-submission")) implementation(testFixtures(project(":jvm-libs:linea:blob-compressor"))) testImplementation("io.vertx:vertx-junit5") + testImplementation(project(":jvm-libs:linea:metrics:micrometer")) } sourceSets { diff --git a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt index 6c4510205..3ab2d0dc2 100644 --- a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppIntTest.kt @@ -17,6 +17,7 @@ import linea.web3j.Web3JLogsSearcher import net.consensys.linea.BlockParameter import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.linea.testing.submission.AggregationAndBlobs import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped import net.consensys.linea.testing.submission.submitBlobsAndAggregationsAndWaitExecution @@ -57,7 +58,10 @@ class StateRecoverAppIntTest { @BeforeEach fun beforeEach(vertx: Vertx) { - val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + val jsonRpcFactory = VertxHttpJsonRpcClientFactory( + vertx = vertx, + metricsFacade = MicrometerMetricsFacade(SimpleMeterRegistry()) + ) aggregationsAndBlobs = loadBlobsAndAggregationsSortedAndGrouped( blobsResponsesDir = "$testDataDir/compression/responses", aggregationsResponsesDir = "$testDataDir/aggregation/responses" diff --git a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt index efd811266..b6a81809b 100644 --- a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoverAppWithFakeExecutionClientIntTest.kt @@ -18,6 +18,7 @@ import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.BlockParameter import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.linea.testing.submission.AggregationAndBlobs import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped import net.consensys.linea.testing.submission.submitBlobsAndAggregationsAndWaitExecution @@ -58,7 +59,10 @@ class StateRecoverAppWithFakeExecutionClientIntTest { @BeforeEach fun beforeEach(vertx: Vertx) { - val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + val jsonRpcFactory = VertxHttpJsonRpcClientFactory( + vertx = vertx, + metricsFacade = MicrometerMetricsFacade(SimpleMeterRegistry()) + ) aggregationsAndBlobs = loadBlobsAndAggregationsSortedAndGrouped( blobsResponsesDir = "$testDataDir/compression/responses", aggregationsResponsesDir = "$testDataDir/aggregation/responses" diff --git a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt index ee120c173..a0e312dec 100644 --- a/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt +++ b/state-recover/test-cases/src/integrationTest/kotlin/linea/staterecover/StateRecoveryManualReplayToLocalStackIntTest.kt @@ -12,6 +12,7 @@ import linea.web3j.createWeb3jHttpClient import net.consensys.linea.BlockParameter import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.linea.testing.submission.AggregationAndBlobs import net.consensys.linea.testing.submission.loadBlobsAndAggregationsSortedAndGrouped import net.consensys.linea.testing.submission.submitBlobsAndAggregationsAndWaitExecution @@ -42,7 +43,10 @@ class StateRecoveryManualReplayToLocalStackIntTest { @BeforeEach fun beforeEach(vertx: Vertx) { - val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + val jsonRpcFactory = VertxHttpJsonRpcClientFactory( + vertx = vertx, + metricsFacade = MicrometerMetricsFacade(SimpleMeterRegistry()) + ) stateManagerClient = StateManagerV1JsonRpcClient.create( rpcClientFactory = jsonRpcFactory, diff --git a/state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt b/state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt index dfc1c4dc8..ebd9ca5e6 100644 --- a/state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt +++ b/state-recover/test-cases/src/test/kotlin/linea/staterecover/StateRecoverSepoliaWithFakeExecutionClientIntTest.kt @@ -18,6 +18,7 @@ import net.consensys.linea.BlockNumberAndHash import net.consensys.linea.BlockParameter import net.consensys.linea.jsonrpc.client.RequestRetryConfig import net.consensys.linea.jsonrpc.client.VertxHttpJsonRpcClientFactory +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.zkevm.ethereum.Web3jClientManager.buildWeb3Client import org.apache.logging.log4j.Level import org.apache.logging.log4j.LogManager @@ -52,7 +53,10 @@ class StateRecoverSepoliaWithFakeExecutionClientIntTest { @BeforeEach fun beforeEach(vertx: Vertx) { - val jsonRpcFactory = VertxHttpJsonRpcClientFactory(vertx = vertx, meterRegistry = SimpleMeterRegistry()) + val jsonRpcFactory = VertxHttpJsonRpcClientFactory( + vertx = vertx, + metricsFacade = MicrometerMetricsFacade(SimpleMeterRegistry()) + ) executionLayerClient = FakeExecutionLayerClient( headBlock = BlockNumberAndHash(number = 0uL, hash = ByteArray(32) { 0 }), initialStateRecoverStartBlockNumber = null, diff --git a/traces-api-facade/app/build.gradle b/traces-api-facade/app/build.gradle index ea6abeec0..2c6284bd3 100644 --- a/traces-api-facade/app/build.gradle +++ b/traces-api-facade/app/build.gradle @@ -7,6 +7,7 @@ dependencies { implementation project(':traces-api-facade:conflation') implementation project(':traces-api-facade:core') implementation project(':jvm-libs:generic:json-rpc') + implementation project(':jvm-libs:linea:core:metrics') implementation project(':jvm-libs:linea:metrics:micrometer') implementation project(':jvm-libs:generic:extensions:kotlin') implementation project(':jvm-libs:generic:extensions:futures') diff --git a/traces-api-facade/app/src/main/kotlin/net/consensys/linea/traces/app/TracesApiFacadeApp.kt b/traces-api-facade/app/src/main/kotlin/net/consensys/linea/traces/app/TracesApiFacadeApp.kt index 08f93c6fb..33765e951 100644 --- a/traces-api-facade/app/src/main/kotlin/net/consensys/linea/traces/app/TracesApiFacadeApp.kt +++ b/traces-api-facade/app/src/main/kotlin/net/consensys/linea/traces/app/TracesApiFacadeApp.kt @@ -8,6 +8,7 @@ import io.vertx.core.json.jackson.VertxModule import io.vertx.micrometer.backends.BackendRegistries import net.consensys.linea.TracesConflationServiceV1Impl import net.consensys.linea.TracesCountingServiceWithRetry +import net.consensys.linea.metrics.micrometer.MicrometerMetricsFacade import net.consensys.linea.traces.RawJsonTracesConflator import net.consensys.linea.traces.RawJsonTracesCounter import net.consensys.linea.traces.RawJsonTracesCounterV0 @@ -81,12 +82,12 @@ class TracesApiFacadeApp(config: AppConfig) { ) this.api = Api( - config.api, - vertx, - meterRegistry, - semVerValidator, - tracesCounterService, - tracesConflationService + configs = config.api, + vertx = vertx, + metricsFacade = MicrometerMetricsFacade(meterRegistry), + semVerValidator = semVerValidator, + tracesCountingService = tracesCounterService, + tracesConflationService = tracesConflationService ) } diff --git a/traces-api-facade/app/src/main/kotlin/net/consensys/linea/traces/app/api/Api.kt b/traces-api-facade/app/src/main/kotlin/net/consensys/linea/traces/app/api/Api.kt index cce8b114c..4f06158bc 100644 --- a/traces-api-facade/app/src/main/kotlin/net/consensys/linea/traces/app/api/Api.kt +++ b/traces-api-facade/app/src/main/kotlin/net/consensys/linea/traces/app/api/Api.kt @@ -1,6 +1,5 @@ package net.consensys.linea.traces.app.api -import io.micrometer.core.instrument.MeterRegistry import io.vertx.core.DeploymentOptions import io.vertx.core.Future import io.vertx.core.Vertx @@ -11,6 +10,7 @@ import net.consensys.linea.jsonrpc.JsonRpcMessageHandler import net.consensys.linea.jsonrpc.JsonRpcMessageProcessor import net.consensys.linea.jsonrpc.JsonRpcRequestRouter import net.consensys.linea.jsonrpc.httpserver.HttpJsonRpcServer +import net.consensys.linea.metrics.MetricsFacade import net.consensys.linea.vertx.ObservabilityServer data class ApiConfig( @@ -23,7 +23,7 @@ data class ApiConfig( class Api( private val configs: ApiConfig, private val vertx: Vertx, - private val meterRegistry: MeterRegistry, + private val metricsFacade: MetricsFacade, private val semVerValidator: TracesSemanticVersionValidator, private val tracesCountingService: TracesCountingServiceV1, private val tracesConflationService: TracesConflationServiceV1 @@ -43,7 +43,7 @@ class Api( ) val messageHandler: JsonRpcMessageHandler = - JsonRpcMessageProcessor(JsonRpcRequestRouter(requestHandlersV1), meterRegistry) + JsonRpcMessageProcessor(JsonRpcRequestRouter(requestHandlersV1), metricsFacade) val numberOfVerticles: Int = if (configs.numberOfVerticles.toInt() > 0) { diff --git a/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/app/TransactionExclusionApp.kt b/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/app/TransactionExclusionApp.kt index 8144ffd43..8e3472c36 100644 --- a/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/app/TransactionExclusionApp.kt +++ b/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/app/TransactionExclusionApp.kt @@ -129,7 +129,7 @@ class TransactionExclusionApp(config: AppConfig) { Api( configs = config.api, vertx = vertx, - meterRegistry = meterRegistry, + metricsFacade = MicrometerMetricsFacade(meterRegistry), transactionExclusionService = transactionExclusionService ) } diff --git a/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/app/api/Api.kt b/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/app/api/Api.kt index ebb82931e..6d90e43f3 100644 --- a/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/app/api/Api.kt +++ b/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/app/api/Api.kt @@ -1,6 +1,5 @@ package net.consensys.linea.transactionexclusion.app.api -import io.micrometer.core.instrument.MeterRegistry import io.vertx.core.DeploymentOptions import io.vertx.core.Future import io.vertx.core.Vertx @@ -9,6 +8,7 @@ import net.consensys.linea.jsonrpc.JsonRpcMessageHandler import net.consensys.linea.jsonrpc.JsonRpcMessageProcessor import net.consensys.linea.jsonrpc.JsonRpcRequestRouter import net.consensys.linea.jsonrpc.httpserver.HttpJsonRpcServer +import net.consensys.linea.metrics.MetricsFacade import net.consensys.linea.transactionexclusion.TransactionExclusionServiceV1 import net.consensys.linea.vertx.ObservabilityServer @@ -22,7 +22,7 @@ data class ApiConfig( class Api( private val configs: ApiConfig, private val vertx: Vertx, - private val meterRegistry: MeterRegistry, + private val metricsFacade: MetricsFacade, private val transactionExclusionService: TransactionExclusionServiceV1 ) { private var jsonRpcServerId: String? = null @@ -49,7 +49,7 @@ class Api( ) val messageHandler: JsonRpcMessageHandler = - JsonRpcMessageProcessor(JsonRpcRequestRouter(requestHandlersV1), meterRegistry) + JsonRpcMessageProcessor(JsonRpcRequestRouter(requestHandlersV1), metricsFacade) val numberOfVerticles: Int = if (configs.numberOfVerticles > 0) { diff --git a/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/service/TransactionExclusionServiceV1Impl.kt b/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/service/TransactionExclusionServiceV1Impl.kt index afedd998c..bcbb60680 100644 --- a/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/service/TransactionExclusionServiceV1Impl.kt +++ b/transaction-exclusion-api/app/src/main/kotlin/net/consensys/linea/transactionexclusion/service/TransactionExclusionServiceV1Impl.kt @@ -27,9 +27,9 @@ class TransactionExclusionServiceV1Impl( ) private val txRejectionCounter = metricsFacade.createCounter( - LineaMetricsCategory.TX_EXCLUSION_API, - "transactions.rejected", - "Counter of rejected transactions reported to Transaction Exclusion API service" + category = LineaMetricsCategory.TX_EXCLUSION_API, + name = "transactions.rejected", + description = "Counter of rejected transactions reported to Transaction Exclusion API service" ) override fun saveRejectedTransaction(