Мониторинг приложений Kotlin: библиотека Ktor Metrics и Micrometer

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Мониторинг приложений 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                    

Рекомендаций