Make MetricsCategory an interface and add default tags (#1088)

* Make MetricsCategory an interface and add default tags

* Make metric category non nullable

* Fix jacoco report failure

* fix spotless
This commit is contained in:
Gaurav Ahuja
2025-06-04 14:56:13 -04:00
committed by GitHub
parent 76462593dd
commit 9d20768a5f
10 changed files with 134 additions and 95 deletions

View File

@@ -0,0 +1,9 @@
package net.consensys.linea.metrics
enum class LineaMetricsCategory : MetricsCategory {
AGGREGATION,
BATCH,
BLOB,
CONFLATION,
GAS_PRICE_CAP,
}

View File

@@ -22,6 +22,7 @@ import io.vertx.core.json.JsonObject
import io.vertx.core.json.jackson.DatabindCodec import io.vertx.core.json.jackson.DatabindCodec
import io.vertx.core.json.jackson.VertxModule import io.vertx.core.json.jackson.VertxModule
import io.vertx.ext.auth.User import io.vertx.ext.auth.User
import net.consensys.linea.metrics.MetricsCategory
import net.consensys.linea.metrics.MetricsFacade import net.consensys.linea.metrics.MetricsFacade
import net.consensys.linea.metrics.Tag import net.consensys.linea.metrics.Tag
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
@@ -56,6 +57,9 @@ class JsonRpcMessageProcessor(
private val log: Logger = LogManager.getLogger(JsonRpcMessageProcessor::class.java), private val log: Logger = LogManager.getLogger(JsonRpcMessageProcessor::class.java),
private val responseResultObjectMapper: ObjectMapper = jacksonObjectMapper().registerModules(VertxModule()), private val responseResultObjectMapper: ObjectMapper = jacksonObjectMapper().registerModules(VertxModule()),
private val rpcEnvelopeObjectMapper: ObjectMapper = jacksonObjectMapper(), private val rpcEnvelopeObjectMapper: ObjectMapper = jacksonObjectMapper(),
private val metricsCategory: MetricsCategory = object : MetricsCategory {
override val name: String = "jsonrpc"
},
) : JsonRpcMessageHandler { ) : JsonRpcMessageHandler {
init { init {
DatabindCodec.mapper().registerKotlinModule() DatabindCodec.mapper().registerKotlinModule()
@@ -70,7 +74,8 @@ class JsonRpcMessageProcessor(
): Future<String> { ): Future<String> {
return Future.fromCompletionStage( return Future.fromCompletionStage(
metricsFacade.createDynamicTagTimer<Triple<String?, String, Boolean>>( metricsFacade.createDynamicTagTimer<Triple<String?, String, Boolean>>(
name = "jsonrpc.processing.whole", category = metricsCategory,
name = "processing.whole",
description = "Processing of JSON-RPC message: Deserialization + Business Logic + Serialization", description = "Processing of JSON-RPC message: Deserialization + Business Logic + Serialization",
tagKey = "method", tagKey = "method",
tagValueExtractorOnError = { "METHOD_PROCESSING_ERROR" }, tagValueExtractorOnError = { "METHOD_PROCESSING_ERROR" },
@@ -175,7 +180,8 @@ class JsonRpcMessageProcessor(
responses.first() responses.first()
} else { } else {
metricsFacade.createSimpleTimer<String>( metricsFacade.createSimpleTimer<String>(
name = "jsonrpc.serialization.response.bulk", category = metricsCategory,
name = "serialization.response.bulk",
description = "Time of bulk json response serialization", description = "Time of bulk json response serialization",
).captureTime { responses.joinToString(",", "[", "]") } ).captureTime { responses.joinToString(",", "[", "]") }
} }
@@ -187,7 +193,8 @@ class JsonRpcMessageProcessor(
json: Any, json: Any,
): Result<Pair<JsonRpcRequest, JsonObject>, JsonRpcErrorResponse> { ): Result<Pair<JsonRpcRequest, JsonObject>, JsonRpcErrorResponse> {
return metricsFacade.createDynamicTagTimer( return metricsFacade.createDynamicTagTimer(
name = "jsonrpc.serialization.request", category = metricsCategory,
name = "serialization.request",
description = "json-rpc method parsing", description = "json-rpc method parsing",
tagKey = "method", tagKey = "method",
tagValueExtractorOnError = { "METHOD_PARSE_ERROR" }, tagValueExtractorOnError = { "METHOD_PARSE_ERROR" },
@@ -199,7 +206,8 @@ class JsonRpcMessageProcessor(
private fun encodeAndMeasureResponse(requestContext: RequestContext): String { private fun encodeAndMeasureResponse(requestContext: RequestContext): String {
val timerCapture = metricsFacade.createSimpleTimer<String>( val timerCapture = metricsFacade.createSimpleTimer<String>(
name = "jsonrpc.serialization.response", category = metricsCategory,
name = "serialization.response",
description = "Time of json response serialization", description = "Time of json response serialization",
tags = listOf(Tag("method", requestContext.method)), tags = listOf(Tag("method", requestContext.method)),
) )
@@ -219,7 +227,8 @@ class JsonRpcMessageProcessor(
requestJson: JsonObject, requestJson: JsonObject,
): Future<Result<JsonRpcSuccessResponse, JsonRpcErrorResponse>> { ): Future<Result<JsonRpcSuccessResponse, JsonRpcErrorResponse>> {
return metricsFacade.createSimpleTimer<Future<Result<JsonRpcSuccessResponse, JsonRpcErrorResponse>>>( return metricsFacade.createSimpleTimer<Future<Result<JsonRpcSuccessResponse, JsonRpcErrorResponse>>>(
name = "jsonrpc.processing.logic", category = metricsCategory,
name = "processing.logic",
description = "Processing of a particular JRPC method's logic without SerDes", description = "Processing of a particular JRPC method's logic without SerDes",
tags = listOf(Tag("method", jsonRpcRequest.method)), tags = listOf(Tag("method", jsonRpcRequest.method)),
) )
@@ -227,7 +236,8 @@ class JsonRpcMessageProcessor(
.onComplete { result: AsyncResult<Result<JsonRpcSuccessResponse, JsonRpcErrorResponse>> -> .onComplete { result: AsyncResult<Result<JsonRpcSuccessResponse, JsonRpcErrorResponse>> ->
val success = (result.succeeded() && result.result() is Ok) val success = (result.succeeded() && result.result() is Ok)
metricsFacade.createCounter( metricsFacade.createCounter(
name = "jsonrpc.counter", category = metricsCategory,
name = "counter",
description = "Counting the JSON rpc request with result and method", description = "Counting the JSON rpc request with result and method",
tags = listOf( tags = listOf(
Tag("success", success.toString()), Tag("success", success.toString()),

View File

@@ -18,6 +18,7 @@ import net.consensys.linea.jsonrpc.JsonRpcErrorResponse
import net.consensys.linea.jsonrpc.JsonRpcRequest import net.consensys.linea.jsonrpc.JsonRpcRequest
import net.consensys.linea.jsonrpc.JsonRpcRequestData import net.consensys.linea.jsonrpc.JsonRpcRequestData
import net.consensys.linea.jsonrpc.JsonRpcSuccessResponse import net.consensys.linea.jsonrpc.JsonRpcSuccessResponse
import net.consensys.linea.metrics.MetricsCategory
import net.consensys.linea.metrics.MetricsFacade import net.consensys.linea.metrics.MetricsFacade
import net.consensys.linea.metrics.Tag import net.consensys.linea.metrics.Tag
import org.apache.logging.log4j.Level import org.apache.logging.log4j.Level
@@ -35,6 +36,9 @@ class VertxHttpJsonRpcClient(
private val log: Logger = LogManager.getLogger(VertxHttpJsonRpcClient::class.java), private val log: Logger = LogManager.getLogger(VertxHttpJsonRpcClient::class.java),
private val requestResponseLogLevel: Level = Level.TRACE, private val requestResponseLogLevel: Level = Level.TRACE,
private val failuresLogLevel: Level = Level.DEBUG, private val failuresLogLevel: Level = Level.DEBUG,
private val metricsCategory: MetricsCategory = object : MetricsCategory {
override val name: String = "jsonrpc"
},
) : JsonRpcClient { ) : JsonRpcClient {
private val requestOptions = RequestOptions().apply { private val requestOptions = RequestOptions().apply {
setMethod(HttpMethod.POST) setMethod(HttpMethod.POST)
@@ -87,7 +91,8 @@ class VertxHttpJsonRpcClient(
Future.fromCompletionStage( Future.fromCompletionStage(
metricsFacade.createSimpleTimer<Result<JsonRpcSuccessResponse, JsonRpcErrorResponse>>( metricsFacade.createSimpleTimer<Result<JsonRpcSuccessResponse, JsonRpcErrorResponse>>(
name = "jsonrpc.request", category = metricsCategory,
name = "request",
description = "Time of Upstream API JsonRpc Requests", description = "Time of Upstream API JsonRpc Requests",
tags = listOf( tags = listOf(
Tag("endpoint", endpoint.host), Tag("endpoint", endpoint.host),

View File

@@ -7,18 +7,8 @@ import java.util.function.Supplier
data class Tag(val key: String, val value: String) data class Tag(val key: String, val value: String)
enum class LineaMetricsCategory { interface MetricsCategory {
AGGREGATION, val name: String
BATCH,
BLOB,
CONFLATION,
GAS_PRICE_CAP,
TX_EXCLUSION_API,
;
override fun toString(): String {
return this.name.replace('_', '.').lowercase()
}
} }
interface Counter { interface Counter {
@@ -38,7 +28,7 @@ interface TimerCapture<T> {
interface MetricsFacade { interface MetricsFacade {
fun createGauge( fun createGauge(
category: LineaMetricsCategory? = null, category: MetricsCategory,
name: String, name: String,
description: String, description: String,
measurementSupplier: Supplier<Number>, measurementSupplier: Supplier<Number>,
@@ -46,14 +36,14 @@ interface MetricsFacade {
) )
fun createCounter( fun createCounter(
category: LineaMetricsCategory? = null, category: MetricsCategory,
name: String, name: String,
description: String, description: String,
tags: List<Tag> = emptyList(), tags: List<Tag> = emptyList(),
): Counter ): Counter
fun createHistogram( fun createHistogram(
category: LineaMetricsCategory? = null, category: MetricsCategory,
name: String, name: String,
description: String, description: String,
tags: List<Tag> = emptyList(), tags: List<Tag> = emptyList(),
@@ -62,14 +52,14 @@ interface MetricsFacade {
): Histogram ): Histogram
fun <T> createSimpleTimer( fun <T> createSimpleTimer(
category: LineaMetricsCategory? = null, category: MetricsCategory,
name: String, name: String,
description: String, description: String,
tags: List<Tag> = emptyList(), tags: List<Tag> = emptyList(),
): TimerCapture<T> ): TimerCapture<T>
fun <T> createDynamicTagTimer( fun <T> createDynamicTagTimer(
category: LineaMetricsCategory? = null, category: MetricsCategory,
name: String, name: String,
description: String, description: String,
tagKey: String, tagKey: String,

View File

@@ -21,10 +21,6 @@ class DynamicTagTimerCapture<T> : AbstractTimerCapture<T>, TimerCapture<T> {
private var tagKey: String? = null private var tagKey: String? = null
constructor(meterRegistry: MeterRegistry, name: String) : super(meterRegistry, name) constructor(meterRegistry: MeterRegistry, name: String) : super(meterRegistry, name)
constructor(
meterRegistry: MeterRegistry,
timerBuilder: Timer.Builder,
) : super(meterRegistry, timerBuilder)
override fun setDescription(description: String): DynamicTagTimerCapture<T> { override fun setDescription(description: String): DynamicTagTimerCapture<T> {
super.setDescription(description) super.setDescription(description)
@@ -32,9 +28,8 @@ class DynamicTagTimerCapture<T> : AbstractTimerCapture<T>, TimerCapture<T> {
} }
override fun setTag(tagKey: String, tagValue: String): DynamicTagTimerCapture<T> { override fun setTag(tagKey: String, tagValue: String): DynamicTagTimerCapture<T> {
throw NoSuchMethodException( super.setTag(tagKey, tagValue)
"If you need to set both value and key, please use ${SimpleTimerCapture::class.qualifiedName}", return this
)
} }
override fun setClock(clock: Clock): DynamicTagTimerCapture<T> { override fun setClock(clock: Clock): DynamicTagTimerCapture<T> {

View File

@@ -0,0 +1,7 @@
package net.consensys.linea.metrics.micrometer
import net.consensys.linea.metrics.MetricsCategory
fun MetricsCategory.toValidMicrometerName(): String {
return this.name.lowercase().replace('_', '.')
}

View File

@@ -5,7 +5,7 @@ import io.micrometer.core.instrument.Gauge
import io.micrometer.core.instrument.MeterRegistry import io.micrometer.core.instrument.MeterRegistry
import net.consensys.linea.metrics.Counter import net.consensys.linea.metrics.Counter
import net.consensys.linea.metrics.Histogram import net.consensys.linea.metrics.Histogram
import net.consensys.linea.metrics.LineaMetricsCategory import net.consensys.linea.metrics.MetricsCategory
import net.consensys.linea.metrics.MetricsFacade import net.consensys.linea.metrics.MetricsFacade
import net.consensys.linea.metrics.Tag import net.consensys.linea.metrics.Tag
import net.consensys.linea.metrics.TimerCapture import net.consensys.linea.metrics.TimerCapture
@@ -17,6 +17,7 @@ import io.micrometer.core.instrument.Timer as MicrometerTimer
class MicrometerMetricsFacade( class MicrometerMetricsFacade(
private val registry: MeterRegistry, private val registry: MeterRegistry,
private val metricsPrefix: String? = null, private val metricsPrefix: String? = null,
private val commonTags: List<Tag> = emptyList(),
) : MetricsFacade { ) : MetricsFacade {
companion object { companion object {
private val validBaseUnits = listOf( private val validBaseUnits = listOf(
@@ -37,74 +38,64 @@ class MicrometerMetricsFacade(
init { init {
if (metricsPrefix != null) requireValidMicrometerName(metricsPrefix) if (metricsPrefix != null) requireValidMicrometerName(metricsPrefix)
commonTags.forEach { requireValidMicrometerName(it.key) }
} }
private fun metricHandle(category: LineaMetricsCategory?, metricName: String): String { private fun metricHandle(category: MetricsCategory, metricName: String): String {
val prefixName = if (metricsPrefix == null) "" else "$metricsPrefix." val prefixName = if (metricsPrefix == null) "" else "$metricsPrefix."
val categoryName = if (category == null) "" else "$category." val categoryName = "${category.toValidMicrometerName()}."
return "$prefixName$categoryName$metricName" return "$prefixName$categoryName$metricName"
} }
private fun flattenTags(tags: List<Tag>): List<String> {
tags.forEach { requireValidMicrometerName(it.key) }
return (tags + commonTags).flatMap {
listOf(it.key, it.value)
}
}
override fun createGauge( override fun createGauge(
category: LineaMetricsCategory?, category: MetricsCategory,
name: String, name: String,
description: String, description: String,
measurementSupplier: Supplier<Number>, measurementSupplier: Supplier<Number>,
tags: List<Tag>, tags: List<Tag>,
) { ) {
if (category != null) requireValidMicrometerName(category.toString()) requireValidMicrometerName(category.toValidMicrometerName())
requireValidMicrometerName(name) requireValidMicrometerName(name)
val builder = Gauge.builder(metricHandle(category, name), measurementSupplier) val builder = Gauge.builder(metricHandle(category, name), measurementSupplier)
if (tags.isNotEmpty()) { flattenTags(tags).takeIf { it.isNotEmpty() }?.let { builder.tags(*it.toTypedArray()) }
val flatTags = tags.flatMap {
requireValidMicrometerName(it.key)
listOf(it.key, it.value)
}
builder.tags(*flatTags.toTypedArray())
}
builder.description(description) builder.description(description)
builder.register(registry) builder.register(registry)
} }
override fun createCounter( override fun createCounter(
category: LineaMetricsCategory?, category: MetricsCategory,
name: String, name: String,
description: String, description: String,
tags: List<Tag>, tags: List<Tag>,
): Counter { ): Counter {
if (category != null) requireValidMicrometerName(category.toString()) requireValidMicrometerName(category.toValidMicrometerName())
requireValidMicrometerName(name) requireValidMicrometerName(name)
val builder = MicrometerCounter.builder(metricHandle(category, name)) val builder = MicrometerCounter.builder(metricHandle(category, name))
if (tags.isNotEmpty()) { flattenTags(tags).takeIf { it.isNotEmpty() }?.let { builder.tags(*it.toTypedArray()) }
val flatTags = tags.flatMap {
requireValidMicrometerName(it.key)
listOf(it.key, it.value)
}
builder.tags(*flatTags.toTypedArray())
}
builder.description(description) builder.description(description)
return MicrometerCounterAdapter(builder.register(registry)) return MicrometerCounterAdapter(builder.register(registry))
} }
override fun createHistogram( override fun createHistogram(
category: LineaMetricsCategory?, category: MetricsCategory,
name: String, name: String,
description: String, description: String,
tags: List<Tag>, tags: List<Tag>,
isRatio: Boolean, isRatio: Boolean,
baseUnit: String?, baseUnit: String?,
): Histogram { ): Histogram {
if (category != null) requireValidMicrometerName(category.toString()) requireValidMicrometerName(category.toValidMicrometerName())
requireValidMicrometerName(name) requireValidMicrometerName(name)
if (baseUnit != null) requireValidBaseUnit(baseUnit) if (baseUnit != null) requireValidBaseUnit(baseUnit)
val distributionSummaryBuilder = DistributionSummary.builder(metricHandle(category, name)) val distributionSummaryBuilder = DistributionSummary.builder(metricHandle(category, name))
if (tags.isNotEmpty()) { flattenTags(tags).takeIf { it.isNotEmpty() }?.let { distributionSummaryBuilder.tags(*it.toTypedArray()) }
val flatTags = tags.flatMap {
requireValidMicrometerName(it.key)
listOf(it.key, it.value)
}
distributionSummaryBuilder.tags(*flatTags.toTypedArray())
}
distributionSummaryBuilder.description(description) distributionSummaryBuilder.description(description)
distributionSummaryBuilder.baseUnit(baseUnit) distributionSummaryBuilder.baseUnit(baseUnit)
if (isRatio) { if (isRatio) {
@@ -115,41 +106,37 @@ class MicrometerMetricsFacade(
} }
override fun <T> createSimpleTimer( override fun <T> createSimpleTimer(
category: LineaMetricsCategory?, category: MetricsCategory,
name: String, name: String,
description: String, description: String,
tags: List<Tag>, tags: List<Tag>,
): TimerCapture<T> { ): TimerCapture<T> {
if (category != null) requireValidMicrometerName(category.toString()) requireValidMicrometerName(category.toValidMicrometerName())
requireValidMicrometerName(name) requireValidMicrometerName(name)
val builder = MicrometerTimer.builder(metricHandle(category, name)) val builder = MicrometerTimer.builder(metricHandle(category, name))
if (tags.isNotEmpty()) { flattenTags(tags).takeIf { it.isNotEmpty() }?.let { builder.tags(*it.toTypedArray()) }
val flatTags = tags.flatMap {
requireValidMicrometerName(it.key)
listOf(it.key, it.value)
}
builder.tags(*flatTags.toTypedArray())
}
builder.description(description) builder.description(description)
return SimpleTimerCapture(registry, builder) return SimpleTimerCapture(registry, builder)
} }
override fun <T> createDynamicTagTimer( override fun <T> createDynamicTagTimer(
category: LineaMetricsCategory?, category: MetricsCategory,
name: String, name: String,
description: String, description: String,
tagKey: String, tagKey: String,
tagValueExtractorOnError: Function<Throwable, String>, tagValueExtractorOnError: Function<Throwable, String>,
tagValueExtractor: Function<T, String>, tagValueExtractor: Function<T, String>,
): TimerCapture<T> { ): TimerCapture<T> {
if (category != null) requireValidMicrometerName(category.toString()) requireValidMicrometerName(category.toValidMicrometerName())
requireValidMicrometerName(name) requireValidMicrometerName(name)
requireValidMicrometerName(tagKey) requireValidMicrometerName(tagKey)
return DynamicTagTimerCapture<T>(registry, metricHandle(category, name)) val dynamicTagTimerCapture = DynamicTagTimerCapture<T>(registry, metricHandle(category, name))
.setDescription(description) .setDescription(description)
.setTagKey(tagKey) .setTagKey(tagKey)
.setTagValueExtractor(tagValueExtractor) .setTagValueExtractor(tagValueExtractor)
.setTagValueExtractorOnError(tagValueExtractorOnError) .setTagValueExtractorOnError(tagValueExtractorOnError)
commonTags.forEach { dynamicTagTimerCapture.setTag(it.key, it.value) }
return dynamicTagTimerCapture
} }
} }

View File

@@ -3,7 +3,7 @@ package net.consensys.linea.metrics.micrometer
import io.micrometer.core.instrument.ImmutableTag import io.micrometer.core.instrument.ImmutableTag
import io.micrometer.core.instrument.MeterRegistry import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.simple.SimpleMeterRegistry import io.micrometer.core.instrument.simple.SimpleMeterRegistry
import net.consensys.linea.metrics.LineaMetricsCategory import net.consensys.linea.metrics.MetricsCategory
import net.consensys.linea.metrics.MetricsFacade import net.consensys.linea.metrics.MetricsFacade
import net.consensys.linea.metrics.Tag import net.consensys.linea.metrics.Tag
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
@@ -16,10 +16,18 @@ class MicrometerMetricsFacadeTest {
private lateinit var meterRegistry: MeterRegistry private lateinit var meterRegistry: MeterRegistry
private lateinit var metricsFacade: MetricsFacade private lateinit var metricsFacade: MetricsFacade
enum class TestCategory : MetricsCategory {
TEST_CATEGORY,
}
@BeforeEach @BeforeEach
fun beforeEach() { fun beforeEach() {
meterRegistry = SimpleMeterRegistry() meterRegistry = SimpleMeterRegistry()
metricsFacade = MicrometerMetricsFacade(meterRegistry, "linea.test") metricsFacade = MicrometerMetricsFacade(
meterRegistry,
metricsPrefix = "linea.test",
commonTags = listOf(Tag("version", "1.0.1")),
)
} }
@Test @Test
@@ -27,19 +35,23 @@ class MicrometerMetricsFacadeTest {
var metricMeasureValue = 0L var metricMeasureValue = 0L
val expectedTags = listOf(Tag("key1", "value1"), Tag("key2", "value2")) val expectedTags = listOf(Tag("key1", "value1"), Tag("key2", "value2"))
metricsFacade.createGauge( metricsFacade.createGauge(
category = LineaMetricsCategory.BATCH, category = TestCategory.TEST_CATEGORY,
name = "some.metric", name = "some.metric",
description = "This is a test metric", description = "This is a test metric",
measurementSupplier = { metricMeasureValue }, measurementSupplier = { metricMeasureValue },
tags = expectedTags, tags = expectedTags,
) )
metricMeasureValue = 13L metricMeasureValue = 13L
val createdGauge = meterRegistry.find("linea.test.batch.some.metric").gauge() val createdGauge = meterRegistry.find("linea.test.test.category.some.metric").gauge()
assertThat(createdGauge).isNotNull assertThat(createdGauge).isNotNull
assertThat(createdGauge!!.value()).isEqualTo(13.0) assertThat(createdGauge!!.value()).isEqualTo(13.0)
metricMeasureValue = 2L metricMeasureValue = 2L
assertThat(createdGauge.value()).isEqualTo(2.0) assertThat(createdGauge.value()).isEqualTo(2.0)
assertThat(createdGauge.id.tags).isEqualTo(listOf(ImmutableTag("key1", "value1"), ImmutableTag("key2", "value2"))) assertThat(
createdGauge.id.tags,
).containsAll(
listOf(ImmutableTag("version", "1.0.1"), ImmutableTag("key1", "value1"), ImmutableTag("key2", "value2")),
)
assertThat(createdGauge.id.description).isEqualTo("This is a test metric") assertThat(createdGauge.id.description).isEqualTo("This is a test metric")
} }
@@ -47,12 +59,12 @@ class MicrometerMetricsFacadeTest {
fun `createCounter creates counter with specified parameters`() { fun `createCounter creates counter with specified parameters`() {
val expectedTags = listOf(Tag("key1", "value1"), Tag("key2", "value2")) val expectedTags = listOf(Tag("key1", "value1"), Tag("key2", "value2"))
val counter = metricsFacade.createCounter( val counter = metricsFacade.createCounter(
category = LineaMetricsCategory.BATCH, category = TestCategory.TEST_CATEGORY,
name = "some.metric", name = "some.metric",
description = "This is a test metric", description = "This is a test metric",
tags = expectedTags, tags = expectedTags,
) )
val createdCounter = meterRegistry.find("linea.test.batch.some.metric").counter() val createdCounter = meterRegistry.find("linea.test.test.category.some.metric").counter()
assertThat(createdCounter!!.count()).isEqualTo(0.0) assertThat(createdCounter!!.count()).isEqualTo(0.0)
assertThat(createdCounter).isNotNull assertThat(createdCounter).isNotNull
counter.increment(13.0) counter.increment(13.0)
@@ -64,7 +76,11 @@ class MicrometerMetricsFacadeTest {
assertThat(createdCounter.count()).isEqualTo(16.0) assertThat(createdCounter.count()).isEqualTo(16.0)
counter.increment(0.5) counter.increment(0.5)
assertThat(createdCounter.count()).isEqualTo(16.5) assertThat(createdCounter.count()).isEqualTo(16.5)
assertThat(createdCounter.id.tags).isEqualTo(listOf(ImmutableTag("key1", "value1"), ImmutableTag("key2", "value2"))) assertThat(
createdCounter.id.tags,
).containsAll(
listOf(ImmutableTag("version", "1.0.1"), ImmutableTag("key1", "value1"), ImmutableTag("key2", "value2")),
)
assertThat(createdCounter.id.description).isEqualTo("This is a test metric") assertThat(createdCounter.id.description).isEqualTo("This is a test metric")
} }
@@ -72,18 +88,20 @@ class MicrometerMetricsFacadeTest {
fun `createHistogram creates histogram with specified parameters`() { fun `createHistogram creates histogram with specified parameters`() {
val expectedTags = listOf(Tag("key1", "value1"), Tag("key2", "value2")) val expectedTags = listOf(Tag("key1", "value1"), Tag("key2", "value2"))
val histogram = metricsFacade.createHistogram( val histogram = metricsFacade.createHistogram(
category = LineaMetricsCategory.BATCH, category = TestCategory.TEST_CATEGORY,
name = "some.metric", name = "some.metric",
description = "This is a test metric", description = "This is a test metric",
tags = expectedTags, tags = expectedTags,
baseUnit = "seconds", baseUnit = "seconds",
) )
val createdHistogram = meterRegistry.find("linea.test.batch.some.metric").summary() val createdHistogram = meterRegistry.find("linea.test.test.category.some.metric").summary()
assertThat(createdHistogram).isNotNull assertThat(createdHistogram).isNotNull
assertThat(createdHistogram!!.id.description).isEqualTo("This is a test metric") assertThat(createdHistogram!!.id.description).isEqualTo("This is a test metric")
assertThat(createdHistogram.id.tags).isEqualTo( assertThat(
listOf(ImmutableTag("key1", "value1"), ImmutableTag("key2", "value2")), createdHistogram.id.tags,
).containsAll(
listOf(ImmutableTag("version", "1.0.1"), ImmutableTag("key1", "value1"), ImmutableTag("key2", "value2")),
) )
assertThat(createdHistogram.id.baseUnit).isEqualTo("seconds") assertThat(createdHistogram.id.baseUnit).isEqualTo("seconds")
assertThat(createdHistogram.count()).isEqualTo(0L) assertThat(createdHistogram.count()).isEqualTo(0L)
@@ -113,16 +131,21 @@ class MicrometerMetricsFacadeTest {
val expectedTags = listOf(Tag("key1", "value1"), Tag("key2", "value2")) val expectedTags = listOf(Tag("key1", "value1"), Tag("key2", "value2"))
val timer = metricsFacade.createSimpleTimer<Unit>( val timer = metricsFacade.createSimpleTimer<Unit>(
category = TestCategory.TEST_CATEGORY,
name = "some.timer.metric", name = "some.timer.metric",
description = "This is a test metric", description = "This is a test metric",
tags = expectedTags, tags = expectedTags,
) )
timer.captureTime(::mockTimer) timer.captureTime(::mockTimer)
val createdTimer = meterRegistry.find("linea.test.some.timer.metric").timer() val createdTimer = meterRegistry.find("linea.test.test.category.some.timer.metric").timer()
assertThat(createdTimer).isNotNull assertThat(createdTimer).isNotNull
assertThat(createdTimer!!.id.description).isEqualTo("This is a test metric") assertThat(createdTimer!!.id.description).isEqualTo("This is a test metric")
assertThat(createdTimer.id.tags).isEqualTo(listOf(ImmutableTag("key1", "value1"), ImmutableTag("key2", "value2"))) assertThat(
createdTimer.id.tags,
).containsAll(
listOf(ImmutableTag("version", "1.0.1"), ImmutableTag("key1", "value1"), ImmutableTag("key2", "value2")),
)
assertThat(createdTimer.max(TimeUnit.SECONDS)).isGreaterThan(0.2) assertThat(createdTimer.max(TimeUnit.SECONDS)).isGreaterThan(0.2)
timer.captureTime(::mockTimer) timer.captureTime(::mockTimer)
@@ -137,6 +160,7 @@ class MicrometerMetricsFacadeTest {
} }
val timer = metricsFacade.createDynamicTagTimer<Unit>( val timer = metricsFacade.createDynamicTagTimer<Unit>(
category = TestCategory.TEST_CATEGORY,
name = "some.dynamictag.timer.metric", name = "some.dynamictag.timer.metric",
description = "This is a test metric", description = "This is a test metric",
tagKey = "key", tagKey = "key",
@@ -146,10 +170,10 @@ class MicrometerMetricsFacadeTest {
} }
timer.captureTime(::mockTimer) timer.captureTime(::mockTimer)
val createdTimer = meterRegistry.find("linea.test.some.dynamictag.timer.metric").timer() val createdTimer = meterRegistry.find("linea.test.test.category.some.dynamictag.timer.metric").timer()
assertThat(createdTimer).isNotNull assertThat(createdTimer).isNotNull
assertThat(createdTimer!!.id.description).isEqualTo("This is a test metric") assertThat(createdTimer!!.id.description).isEqualTo("This is a test metric")
assertThat(createdTimer.id.tags).isEqualTo(listOf(ImmutableTag("key", "value"))) assertThat(createdTimer.id.tags).containsAll(listOf(ImmutableTag("version", "1.0.1"), ImmutableTag("key", "value")))
assertThat(createdTimer.max(TimeUnit.SECONDS)).isGreaterThan(0.2) assertThat(createdTimer.max(TimeUnit.SECONDS)).isGreaterThan(0.2)
timer.captureTime(::mockTimer) timer.captureTime(::mockTimer)
@@ -163,12 +187,13 @@ class MicrometerMetricsFacadeTest {
val meterRegistry = SimpleMeterRegistry() val meterRegistry = SimpleMeterRegistry()
val metricsFacade = MicrometerMetricsFacade(meterRegistry) val metricsFacade = MicrometerMetricsFacade(meterRegistry)
metricsFacade.createGauge( metricsFacade.createGauge(
category = TestCategory.TEST_CATEGORY,
name = "some.gauge.metric", name = "some.gauge.metric",
description = "This is a test metric", description = "This is a test metric",
measurementSupplier = { metricMeasureValue }, measurementSupplier = { metricMeasureValue },
tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")), tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")),
) )
val createdGauge = meterRegistry.find("some.gauge.metric").gauge() val createdGauge = meterRegistry.find("test.category.some.gauge.metric").gauge()
assertThat(createdGauge).isNotNull assertThat(createdGauge).isNotNull
} }
@@ -177,11 +202,12 @@ class MicrometerMetricsFacadeTest {
val meterRegistry = SimpleMeterRegistry() val meterRegistry = SimpleMeterRegistry()
val metricsFacade = MicrometerMetricsFacade(meterRegistry) val metricsFacade = MicrometerMetricsFacade(meterRegistry)
metricsFacade.createCounter( metricsFacade.createCounter(
category = TestCategory.TEST_CATEGORY,
name = "some.counter.metric", name = "some.counter.metric",
description = "This is a test metric", description = "This is a test metric",
tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")), tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")),
) )
val createdCounter = meterRegistry.find("some.counter.metric").counter() val createdCounter = meterRegistry.find("test.category.some.counter.metric").counter()
assertThat(createdCounter).isNotNull assertThat(createdCounter).isNotNull
} }
@@ -190,12 +216,13 @@ class MicrometerMetricsFacadeTest {
val meterRegistry = SimpleMeterRegistry() val meterRegistry = SimpleMeterRegistry()
val metricsFacade = MicrometerMetricsFacade(meterRegistry) val metricsFacade = MicrometerMetricsFacade(meterRegistry)
metricsFacade.createHistogram( metricsFacade.createHistogram(
category = TestCategory.TEST_CATEGORY,
name = "some.histogram.metric", name = "some.histogram.metric",
description = "This is a test metric", description = "This is a test metric",
tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")), tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")),
baseUnit = "seconds", baseUnit = "seconds",
) )
val createdHistogram = meterRegistry.find("some.histogram.metric").summary() val createdHistogram = meterRegistry.find("test.category.some.histogram.metric").summary()
assertThat(createdHistogram).isNotNull assertThat(createdHistogram).isNotNull
} }
@@ -204,12 +231,13 @@ class MicrometerMetricsFacadeTest {
val meterRegistry = SimpleMeterRegistry() val meterRegistry = SimpleMeterRegistry()
val metricsFacade = MicrometerMetricsFacade(meterRegistry) val metricsFacade = MicrometerMetricsFacade(meterRegistry)
val timer = metricsFacade.createSimpleTimer<Unit>( val timer = metricsFacade.createSimpleTimer<Unit>(
category = TestCategory.TEST_CATEGORY,
name = "some.timer.metric", name = "some.timer.metric",
description = "This is a test metric", description = "This is a test metric",
tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")), tags = listOf(Tag("key1", "value1"), Tag("key2", "value2")),
) )
timer.captureTime {} timer.captureTime {}
val createdTimer = meterRegistry.find("some.timer.metric").timer() val createdTimer = meterRegistry.find("test.category.some.timer.metric").timer()
assertThat(createdTimer).isNotNull assertThat(createdTimer).isNotNull
} }
@@ -218,6 +246,7 @@ class MicrometerMetricsFacadeTest {
val meterRegistry = SimpleMeterRegistry() val meterRegistry = SimpleMeterRegistry()
val metricsFacade = MicrometerMetricsFacade(meterRegistry) val metricsFacade = MicrometerMetricsFacade(meterRegistry)
val timer = metricsFacade.createDynamicTagTimer<Unit>( val timer = metricsFacade.createDynamicTagTimer<Unit>(
category = TestCategory.TEST_CATEGORY,
name = "some.dynamictag.timer.metric", name = "some.dynamictag.timer.metric",
description = "This is a test metric", description = "This is a test metric",
tagKey = "key", tagKey = "key",
@@ -226,7 +255,7 @@ class MicrometerMetricsFacadeTest {
"value" "value"
} }
timer.captureTime {} timer.captureTime {}
val createdTimer = meterRegistry.find("some.dynamictag.timer.metric").timer() val createdTimer = meterRegistry.find("test.category.some.dynamictag.timer.metric").timer()
assertThat(createdTimer).isNotNull assertThat(createdTimer).isNotNull
} }
} }

View File

@@ -0,0 +1,7 @@
package net.consensys.linea.transactionexclusion.metrics
import net.consensys.linea.metrics.MetricsCategory
enum class LineaMetricsCategory : MetricsCategory {
TX_EXCLUSION_API,
}

View File

@@ -4,13 +4,13 @@ import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Ok import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result import com.github.michaelbull.result.Result
import kotlinx.datetime.Clock import kotlinx.datetime.Clock
import net.consensys.linea.metrics.LineaMetricsCategory
import net.consensys.linea.metrics.MetricsFacade import net.consensys.linea.metrics.MetricsFacade
import net.consensys.linea.transactionexclusion.ErrorType import net.consensys.linea.transactionexclusion.ErrorType
import net.consensys.linea.transactionexclusion.RejectedTransaction import net.consensys.linea.transactionexclusion.RejectedTransaction
import net.consensys.linea.transactionexclusion.TransactionExclusionError import net.consensys.linea.transactionexclusion.TransactionExclusionError
import net.consensys.linea.transactionexclusion.TransactionExclusionServiceV1 import net.consensys.linea.transactionexclusion.TransactionExclusionServiceV1
import net.consensys.linea.transactionexclusion.TransactionExclusionServiceV1.SaveRejectedTransactionStatus import net.consensys.linea.transactionexclusion.TransactionExclusionServiceV1.SaveRejectedTransactionStatus
import net.consensys.linea.transactionexclusion.metrics.LineaMetricsCategory
import net.consensys.zkevm.persistence.dao.rejectedtransaction.RejectedTransactionsDao import net.consensys.zkevm.persistence.dao.rejectedtransaction.RejectedTransactionsDao
import net.consensys.zkevm.persistence.db.DuplicatedRecordException import net.consensys.zkevm.persistence.db.DuplicatedRecordException
import tech.pegasys.teku.infrastructure.async.SafeFuture import tech.pegasys.teku.infrastructure.async.SafeFuture