Prometheus Metrics in Kotlin: From Basics to Production Solutions
Modern backend applications require constant monitoring. Prometheus is the de facto standard for metrics collection in the microservices world. In this article, we will explore how to integrate Prometheus into Kotlin applications using the Micrometer library and the Ktor framework. You will learn how to create custom counters, histograms, and timers, as well as configure an endpoint for metrics collection.
1. Why Micrometer?
Micrometer is a monitoring facade, similar to SLF4J for logging. It supports many backends: Prometheus, Graphite, Datadog, InfluxDB, and others. By using Micrometer, you are not tied to a specific monitoring system — you simply change the dependency.
For Prometheus, Micrometer provides a special registry PrometheusMeterRegistry, which exports metrics in a text format understandable by Prometheus.
2. Adding Dependencies
Add the following dependencies to your build.gradle.kts:
dependencies { // Micrometer + Prometheus implementation("io.micrometer:micrometer-core:1.12.5") implementation("io.micrometer:micrometer-registry-prometheus:1.12.5")
// For Ktor implementation("io.ktor:ktor-server-core:2.3.9") implementation("io.ktor:ktor-server-netty:2.3.9") implementation("io.ktor:ktor-server-metrics-micrometer:2.3.9")}If you are using Spring Boot, simply add spring-boot-starter-actuator and micrometer-registry-prometheus — Spring Boot will automatically configure the /actuator/prometheus endpoint.
3. Basic Setup in Ktor
Let's create a simple Ktor application with Prometheus metrics. We will need:
PrometheusMeterRegistry— the metrics registryKtorMetricsPlugin— a plugin for automatic HTTP metrics collection- A
/metricsendpoint for Prometheus to scrape
import io.ktor.server.application.*import io.ktor.server.engine.*import io.ktor.server.netty.*import io.ktor.server.response.*import io.ktor.server.routing.*import io.micrometer.prometheus.PrometheusConfigimport io.micrometer.prometheus.PrometheusMeterRegistryimport io.ktor.server.plugins.metrics.micrometer.*
fun main() { val prometheusRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
embeddedServer(Netty, port = 8080) { install(MicrometerMetrics) { registry = prometheusRegistry // Enable default metrics collection (JVM, CPU, memory) meterBinders = listOf( JvmGcMetrics(), JvmMemoryMetrics(), ProcessorMetrics() ) }
routing { // Endpoint for Prometheus get("/metrics") { call.respondText( contentType = ContentType.parse("text/plain; version=0.0.4"), text = prometheusRegistry.scrape() ) }
// Example business endpoint get("/hello") { call.respondText("Hello, Kotlin!") } } }.start(wait = true)}4. Custom Metrics
In addition to automatic metrics, you can create your own. Let's look at three main types:
- Counter — a counter (e.g., number of requests)
- Timer — execution time of an operation
- Gauge — a current value (e.g., number of active users)
import io.micrometer.core.instrument.Counterimport io.micrometer.core.instrument.Timerimport io.micrometer.core.instrument.Gauge
// Create metricsval requestCounter: Counter = Counter .builder(