Monitoring Kotlin Applications: Ktor Metrics and Micrometer
Modern server-side Kotlin applications built on the Ktor framework require constant monitoring of performance and status. For this purpose, a combination of two powerful tools is used: Ktor Metrics Plugin (a built-in Ktor module) and Micrometer (a facade for collecting metrics). In this article, we will cover how to set up monitoring with data export to Prometheus and visualization in Grafana.
Why is monitoring needed?
Monitoring allows you to:
- Track endpoint response time (latency).
- Count the number of requests (RPS).
- Identify slow requests and errors.
- Monitor memory and CPU usage (via JVM metrics).
- Configure alerts when thresholds are exceeded.
Libraries and Dependencies
The following dependencies are required in build.gradle.kts:
dependencies { // Ktor Server implementation("io.ktor:ktor-server-core:2.3.7") implementation("io.ktor:ktor-server-netty:2.3.7")
// Metrics Plugin implementation("io.ktor:ktor-server-metrics-micrometer:2.3.7")
// Prometheus Export implementation("io.micrometer:micrometer-registry-prometheus:1.12.0")
// JVM Metrics (optional) implementation("io.micrometer:micrometer-core:1.12.0")}Basic Ktor Metrics Configuration
Let's look at a simple server example with metrics. Create a file Application.kt:
import io.ktor.server.application.*import io.ktor.server.engine.*import io.ktor.server.netty.*import io.ktor.server.routing.*import io.ktor.server.response.*import io.ktor.server.metrics.micrometer.*import io.micrometer.prometheus.PrometheusMeterRegistryimport io.micrometer.prometheus.PrometheusConfig
fun main() { embeddedServer(Netty, port = 8080) { // Create a Prometheus metric registry val prometheusRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
// Install the metrics plugin install(MicrometerMetrics) { registry = prometheusRegistry // Default metric names meterBinders = listOf( // Add JVM metrics io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics(), io.micrometer.core.instrument.binder.system.ProcessorMetrics() ) }
// Routing routing { // Endpoint for serving Prometheus metrics get("/metrics") { call.respond(prometheusRegistry.scrape()) }
// Test endpoint get("/hello") { call.respondText("Hello, World!") }
// Endpoint with artificial delay get("/slow") { Thread.sleep(500) call.respondText("Slow response") } } }.start(wait = true)}After starting the server, open http://localhost:8080/metrics — you will see metrics in Prometheus format:
# HELP ktor_http_server_requests_seconds # TYPE ktor_http_server_requests_seconds summaryktor_http_server_requests_seconds_count{method="GET",route="/hello",status="2xx"} 3.0ktor_http_server_requests_seconds_sum{method="GET",route="/hello",status="2xx"} 0.012# HELP jvm_memory_used_bytes # TYPE jvm_memory_used_bytes gaugejvm_memory_used_bytes{area="heap",id="G1 Survivor Space"} 1048576.0Advanced Configuration: Custom Metrics
You can add your own counters and timers. For example, a counter for processed orders:
import io.micrometer.core.instrument.Counterimport io.micrometer.core.instrument.MeterRegistry
Also in library
Monitoring Rust Applications with the tracing Library
Working with XML in PHP: Parsing, Creating, and Processing Data
Integrating Prometheus Metrics in Kotlin Applications: A Complete Guide
Crow for C++: Complete Guide with Examples