From 52fa92b59787fde204d194cb38bfb310161c05b2 Mon Sep 17 00:00:00 2001 From: Laszlo Bende Date: Tue, 8 Oct 2024 22:26:48 +0100 Subject: [PATCH 1/2] uptime metric, all metrics tagged with the kafka-cluster Signed-off-by: Laszlo Bende --- .../mwam/kafkakewl/common/metrics/Metrics.kt | 11 +++++++++ .../kafkakewl/common/plugins/Configure.kt | 24 ++++++++++++++++--- .../com/mwam/kafkakewl/deploy/Application.kt | 3 ++- .../kafkakewl/deploy/plugins/Frameworks.kt | 7 ++++++ .../com/mwam/kafkakewl/metrics/Application.kt | 3 ++- .../kafkakewl/metrics/plugins/Frameworks.kt | 7 ++++++ 6 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/metrics/Metrics.kt diff --git a/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/metrics/Metrics.kt b/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/metrics/Metrics.kt new file mode 100644 index 0000000..3cbc3d0 --- /dev/null +++ b/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/metrics/Metrics.kt @@ -0,0 +1,11 @@ +/* + * SPDX-FileCopyrightText: 2024 Marshall Wace + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.mwam.kafkakewl.common.metrics + +fun metricsName(name: String): String { + return "kafkakewl_vext_$name"; +} diff --git a/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/plugins/Configure.kt b/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/plugins/Configure.kt index bac6e63..836f79d 100644 --- a/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/plugins/Configure.kt +++ b/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/plugins/Configure.kt @@ -8,6 +8,7 @@ package com.mwam.kafkakewl.common.plugins import com.auth0.jwt.JWT import com.auth0.jwt.algorithms.Algorithm +import com.mwam.kafkakewl.common.metrics.metricsName import io.github.smiley4.ktorswaggerui.dsl.* import io.ktor.http.* import io.ktor.serialization.kotlinx.json.json @@ -24,8 +25,12 @@ import io.ktor.server.request.httpMethod import io.ktor.server.request.path import io.ktor.server.response.* import io.ktor.server.routing.* +import io.micrometer.core.instrument.Gauge +import io.micrometer.core.instrument.Tag +import io.micrometer.core.instrument.config.MeterFilter import io.micrometer.prometheus.* import kotlinx.serialization.json.Json +import org.koin.ktor.ext.inject import org.slf4j.event.Level /** initializes the logging, sets some logback variables */ @@ -34,21 +39,34 @@ fun initializeLogging(kafkaClusterName: String) { } fun Application.configureMonitoring() { - val appMicrometerRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT) + val meterRegistry by inject() install(MicrometerMetrics) { - registry = appMicrometerRegistry + registry = meterRegistry // ... } routing { get("/metrics", { hidden = true }) { - call.respond(appMicrometerRegistry.scrape()) + call.respond(meterRegistry.scrape()) } } } +fun Application.configureCoreMetrics(kafkaClusterName: String) { + val meterRegistry by inject() + + // registering the kafka-cluster name as a common metrics tag + meterRegistry.config().meterFilter(MeterFilter.commonTags(listOf(Tag.of("kafka_cluster", kafkaClusterName)))) + + var startTimeMillis = System.currentTimeMillis() + + Gauge.builder(metricsName("uptime"), { System.currentTimeMillis() - startTimeMillis }) + .description("the up-time of the service in milliseconds") + .register(meterRegistry) +} + fun Application.configureHealthCheck(name: String, isHealth: () -> Boolean) { routing { get(name, { diff --git a/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/Application.kt b/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/Application.kt index cc9c4e7..1450d93 100644 --- a/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/Application.kt +++ b/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/Application.kt @@ -24,10 +24,11 @@ fun main() { fun Application.module(config: Config) { configureSecurity() configureHTTP() - configureMonitoring() configureSerialization() configureCallLogging() configureFrameworks(config) + configureMonitoring() + configureCoreMetrics(config.kafkaCluster.name) environment.monitor.subscribe(ApplicationStopped) { application -> application.environment.log.info("Ktor server has stopped") diff --git a/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/plugins/Frameworks.kt b/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/plugins/Frameworks.kt index 0d5283a..ed5d070 100644 --- a/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/plugins/Frameworks.kt +++ b/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/plugins/Frameworks.kt @@ -14,14 +14,21 @@ import com.mwam.kafkakewl.deploy.Config import com.mwam.kafkakewl.deploy.services.TopologyDeploymentsService import com.mwam.kafkakewl.deploy.services.TopologyDeploymentsServiceImpl import io.ktor.server.application.* +import io.micrometer.core.instrument.MeterRegistry +import io.micrometer.prometheus.PrometheusConfig +import io.micrometer.prometheus.PrometheusMeterRegistry import org.koin.dsl.module import org.koin.ktor.plugin.Koin import org.koin.logger.slf4jLogger fun Application.configureFrameworks(config: Config) { + val meterRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT) + install(Koin) { slf4jLogger() modules(module { + single { meterRegistry } + single { meterRegistry } single { config } single { (get().kafkaCluster.client) } single { config.kafkaPersistentStore } diff --git a/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/Application.kt b/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/Application.kt index ce3424c..70efec0 100644 --- a/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/Application.kt +++ b/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/Application.kt @@ -27,10 +27,11 @@ fun main() { fun Application.module(config: Config) { configureSecurity() configureHTTP() - configureMonitoring() configureSerialization() configureCallLogging() configureFrameworks(config) + configureMonitoring() + configureCoreMetrics(config.kafkaCluster.name) val kafkaTopicInfoSource by inject() kafkaTopicInfoSource.startPublishing() diff --git a/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/plugins/Frameworks.kt b/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/plugins/Frameworks.kt index 4fb1487..4220805 100644 --- a/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/plugins/Frameworks.kt +++ b/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/plugins/Frameworks.kt @@ -13,14 +13,21 @@ import com.mwam.kafkakewl.common.persistence.PersistentStore import com.mwam.kafkakewl.metrics.Config import com.mwam.kafkakewl.metrics.services.* import io.ktor.server.application.* +import io.micrometer.core.instrument.MeterRegistry +import io.micrometer.prometheus.PrometheusConfig +import io.micrometer.prometheus.PrometheusMeterRegistry import org.koin.dsl.module import org.koin.ktor.plugin.Koin import org.koin.logger.slf4jLogger fun Application.configureFrameworks(config: Config) { + val meterRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT) + install(Koin) { slf4jLogger() modules(module { + single { meterRegistry } + single { meterRegistry } single { config } single { (get().kafkaCluster.client) } single { config.kafkaPersistentStore } From de5e33ab87df89400cbf58cd2ced5b7e3a17ebcf Mon Sep 17 00:00:00 2001 From: Laszlo Bende Date: Wed, 9 Oct 2024 11:28:49 +0100 Subject: [PATCH 2/2] refactoring koin modules so that metrics are separate for code-reuse Signed-off-by: Laszlo Bende --- .../kafkakewl/common/plugins/Configure.kt | 12 ++++++++ .../kafkakewl/deploy/plugins/Frameworks.kt | 28 ++++++++----------- .../kafkakewl/metrics/plugins/Frameworks.kt | 27 ++++++++---------- 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/plugins/Configure.kt b/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/plugins/Configure.kt index 836f79d..3726fe4 100644 --- a/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/plugins/Configure.kt +++ b/kafkakewl-common/src/main/kotlin/com/mwam/kafkakewl/common/plugins/Configure.kt @@ -26,10 +26,13 @@ import io.ktor.server.request.path import io.ktor.server.response.* import io.ktor.server.routing.* import io.micrometer.core.instrument.Gauge +import io.micrometer.core.instrument.MeterRegistry import io.micrometer.core.instrument.Tag import io.micrometer.core.instrument.config.MeterFilter import io.micrometer.prometheus.* import kotlinx.serialization.json.Json +import org.koin.core.module.Module +import org.koin.dsl.module import org.koin.ktor.ext.inject import org.slf4j.event.Level @@ -38,6 +41,15 @@ fun initializeLogging(kafkaClusterName: String) { System.setProperty("LOGBACK_KAFKA_CLUSTER", kafkaClusterName) } +/** creates a koin module with the metrics' PrometheusMeterRegistry */ +fun koinModuleForMetrics(): Module { + val meterRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT) + return module { + single { meterRegistry } + single { meterRegistry } + } +} + fun Application.configureMonitoring() { val meterRegistry by inject() diff --git a/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/plugins/Frameworks.kt b/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/plugins/Frameworks.kt index ed5d070..d45a610 100644 --- a/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/plugins/Frameworks.kt +++ b/kafkakewl-deploy/src/main/kotlin/com/mwam/kafkakewl/deploy/plugins/Frameworks.kt @@ -10,30 +10,26 @@ import com.mwam.kafkakewl.common.config.KafkaClientConfig import com.mwam.kafkakewl.common.config.KafkaPersistentStoreConfig import com.mwam.kafkakewl.common.persistence.KafkaPersistentStore import com.mwam.kafkakewl.common.persistence.PersistentStore +import com.mwam.kafkakewl.common.plugins.koinModuleForMetrics import com.mwam.kafkakewl.deploy.Config -import com.mwam.kafkakewl.deploy.services.TopologyDeploymentsService -import com.mwam.kafkakewl.deploy.services.TopologyDeploymentsServiceImpl +import com.mwam.kafkakewl.deploy.services.* import io.ktor.server.application.* -import io.micrometer.core.instrument.MeterRegistry -import io.micrometer.prometheus.PrometheusConfig -import io.micrometer.prometheus.PrometheusMeterRegistry import org.koin.dsl.module import org.koin.ktor.plugin.Koin import org.koin.logger.slf4jLogger fun Application.configureFrameworks(config: Config) { - val meterRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT) - install(Koin) { slf4jLogger() - modules(module { - single { meterRegistry } - single { meterRegistry } - single { config } - single { (get().kafkaCluster.client) } - single { config.kafkaPersistentStore } - single { KafkaPersistentStore(get(), get()) } - single(createdAtStart=true) { TopologyDeploymentsServiceImpl.create(get()) } - }) + modules( + koinModuleForMetrics(), + module { + single { config } + single { (get().kafkaCluster.client) } + single { config.kafkaPersistentStore } + single { KafkaPersistentStore(get(), get()) } + single(createdAtStart=true) { TopologyDeploymentsServiceImpl.create(get()) } + } + ) } } diff --git a/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/plugins/Frameworks.kt b/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/plugins/Frameworks.kt index 4220805..6ca7348 100644 --- a/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/plugins/Frameworks.kt +++ b/kafkakewl-metrics/src/main/kotlin/com/mwam/kafkakewl/metrics/plugins/Frameworks.kt @@ -10,30 +10,27 @@ import com.mwam.kafkakewl.common.config.KafkaClientConfig import com.mwam.kafkakewl.common.config.KafkaPersistentStoreConfig import com.mwam.kafkakewl.common.persistence.KafkaPersistentStore import com.mwam.kafkakewl.common.persistence.PersistentStore +import com.mwam.kafkakewl.common.plugins.koinModuleForMetrics import com.mwam.kafkakewl.metrics.Config import com.mwam.kafkakewl.metrics.services.* import io.ktor.server.application.* -import io.micrometer.core.instrument.MeterRegistry -import io.micrometer.prometheus.PrometheusConfig -import io.micrometer.prometheus.PrometheusMeterRegistry import org.koin.dsl.module import org.koin.ktor.plugin.Koin import org.koin.logger.slf4jLogger fun Application.configureFrameworks(config: Config) { - val meterRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT) - install(Koin) { slf4jLogger() - modules(module { - single { meterRegistry } - single { meterRegistry } - single { config } - single { (get().kafkaCluster.client) } - single { config.kafkaPersistentStore } - single { KafkaPersistentStore(get(), get()) } - single { KafkaTopicInfoSourceImpl(get(), config.topicInfoSource) } - single(createdAtStart=true) { KafkaTopicInfoCacheImpl(get()) } - }) + modules( + koinModuleForMetrics(), + module { + single { config } + single { (get().kafkaCluster.client) } + single { config.kafkaPersistentStore } + single { KafkaPersistentStore(get(), get()) } + single { KafkaTopicInfoSourceImpl(get(), config.topicInfoSource) } + single(createdAtStart=true) { KafkaTopicInfoCacheImpl(get()) } + } + ) } }