Мониторинг приложений Kotlin: Ktor Metrics и Micrometer
Современные серверные приложения на Kotlin, построенные на фреймворке Ktor, требуют постоянного наблюдения за производительностью и состоянием. Для этого используется связка двух мощных инструментов: Ktor Metrics Plugin (встроенный в Ktor модуль) и Micrometer (фасад для сбора метрик). В этой статье мы разберем, как настроить мониторинг с экспортом данных в Prometheus и отображением в Grafana.
Зачем нужен мониторинг?
Мониторинг позволяет:
- Отслеживать время ответа эндпоинтов (latency).
- Считать количество запросов (RPS).
- Выявлять медленные запросы и ошибки.
- Наблюдать за использованием памяти и CPU (через JVM-метрики).
- Настраивать алерты при превышении порогов.
Библиотеки и зависимости
Для работы потребуются следующие зависимости в build.gradle.kts:
dependencies {
// Ktor Server
implementation("io.ktor:ktor-server-core:2.3.7")
implementation("io.ktor:ktor-server-netty:2.3.7")
// Плагин метрик
implementation("io.ktor:ktor-server-metrics-micrometer:2.3.7")
// Экспорт в Prometheus
implementation("io.micrometer:micrometer-registry-prometheus:1.12.0")
// JVM-метрики (опционально)
implementation("io.micrometer:micrometer-core:1.12.0")
}
Базовая настройка Ktor Metrics
Рассмотрим простой пример сервера с метриками. Создадим файл 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.PrometheusMeterRegistry
import io.micrometer.prometheus.PrometheusConfig
fun main() {
embeddedServer(Netty, port = 8080) {
// Создаем реестр метрик Prometheus
val prometheusRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
// Устанавливаем плагин метрик
install(MicrometerMetrics) {
registry = prometheusRegistry
// Названия метрик по умолчанию
meterBinders = listOf(
// Добавляем JVM-метрики
io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics(),
io.micrometer.core.instrument.binder.system.ProcessorMetrics()
)
}
// Роутинг
routing {
// Эндпоинт для отдачи метрик Prometheus
get("/metrics") {
call.respond(prometheusRegistry.scrape())
}
// Тестовый эндпоинт
get("/hello") {
call.respondText("Hello, World!")
}
// Эндпоинт с искусственной задержкой
get("/slow") {
Thread.sleep(500)
call.respondText("Slow response")
}
}
}.start(wait = true)
}
После запуска сервера откройте http://localhost:8080/metrics — вы увидите метрики в формате Prometheus:
# HELP ktor_http_server_requests_seconds
# TYPE ktor_http_server_requests_seconds summary
ktor_http_server_requests_seconds_count{method="GET",route="/hello",status="2xx"} 3.0
ktor_http_server_requests_seconds_sum{method="GET",route="/hello",status="2xx"} 0.012
# HELP jvm_memory_used_bytes
# TYPE jvm_memory_used_bytes gauge
jvm_memory_used_bytes{area="heap",id="G1 Survivor Space"} 1048576.0
Расширенная настройка: кастомные метрики
Вы можете добавлять собственные счетчики и таймеры. Например, счетчик обработанных заказов:
import io.micrometer.core.instrument.Counter
import io.micrometer.core.instrument.MeterRegistry
// Внутри модуля приложения
class OrderService(private val meterRegistry: MeterRegistry) {
private val orderCounter: Counter = Counter.builder("orders.created")
.description("Total number of created orders")
.register(meterRegistry)
fun createOrder() {
// Логика создания заказа
orderCounter.increment()
}
}
// В main передаем registry
val orderService = OrderService(prometheusRegistry)
Теперь в /metrics появится строка:
orders_created_total 5.0
Интеграция с Prometheus
Чтобы Prometheus забирал метрики, добавьте в prometheus.yml:
scrape_configs:
- job_name: 'kotlin