Prometheus метрики в Kotlin: интеграция с Micrometer и Ktor

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

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

Начать курс

Prometheus метрики в Kotlin: от основ до продакшн-решений

Современные бэкенд-приложения требуют постоянного мониторинга. Prometheus — де-факто стандарт сбора метрик в мире микросервисов. В этой статье мы разберём, как интегрировать Prometheus в Kotlin-приложения с помощью библиотеки Micrometer и фреймворка Ktor. Вы узнаете, как создавать кастомные счётчики, гистограммы и таймеры, а также настроить эндпоинт для сбора метрик.

1. Зачем нужен Micrometer?

Micrometer — это фасад для мониторинга, аналогичный SLF4J для логирования. Он поддерживает множество бэкендов: Prometheus, Graphite, Datadog, InfluxDB и другие. Используя Micrometer, вы не привязываетесь к конкретной системе мониторинга — достаточно сменить зависимость.

Для Prometheus Micrometer предоставляет специальный реестр PrometheusMeterRegistry, который экспортирует метрики в текстовом формате, понятном Prometheus.

2. Подключение зависимостей

Добавьте в build.gradle.kts следующие зависимости:

dependencies {
    // Micrometer + Prometheus
    implementation("io.micrometer:micrometer-core:1.12.5")
    implementation("io.micrometer:micrometer-registry-prometheus:1.12.5")

    // Для 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")
}

Если вы используете Spring Boot, достаточно добавить spring-boot-starter-actuator и micrometer-registry-prometheus — Spring Boot автоматически настроит эндпоинт /actuator/prometheus.

3. Базовая настройка в Ktor

Создадим простое приложение Ktor с Prometheus метриками. Нам потребуется:

  • PrometheusMeterRegistry — реестр метрик
  • KtorMetricsPlugin — плагин для автоматического сбора HTTP-метрик
  • Эндпоинт /metrics для сбора данных Prometheus
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.PrometheusConfig
import io.micrometer.prometheus.PrometheusMeterRegistry
import io.ktor.server.plugins.metrics.micrometer.*

fun main() {
    val prometheusRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)

    embeddedServer(Netty, port = 8080) {
        install(MicrometerMetrics) {
            registry = prometheusRegistry
            // Включаем сбор метрик по умолчанию (JVM, процессор, память)
            meterBinders = listOf(
                JvmGcMetrics(),
                JvmMemoryMetrics(),
                ProcessorMetrics()
            )
        }

        routing {
            // Эндпоинт для Prometheus
            get("/metrics") {
                call.respondText(
                    contentType = ContentType.parse("text/plain; version=0.0.4"),
                    text = prometheusRegistry.scrape()
                )
            }

            // Пример бизнес-эндпоинта
            get("/hello") {
                call.respondText("Hello, Kotlin!")
            }
        }
    }.start(wait = true)
}

4. Кастомные метрики

Помимо автоматических метрик, вы можете создавать свои. Рассмотрим три основных типа:

  • Counter — счётчик (например, количество запросов)
  • Timer — время выполнения операции
  • Gauge — текущее значение (например, количество активных пользователей)
import io.micrometer.core.instrument.Counter
import io.micrometer.core.instrument.Timer
import io.micrometer.core.instrument.Gauge

// Создаём метрики
val requestCounter: Counter = Counter
    .builder("app.requests.total")
    .description("Total number of requests")
    .register(prometheusRegistry)

val responseTimer: Timer = Timer
    .builder("app.response.time")
    .description("Response time in milliseconds")
    .register(prometheusRegistry)

// Использование в эндпоинте
get("/api/data") {
    requestCounter.increment() // увеличиваем счётчик
    val sample = Timer.start() // начинаем замер времени
    val result = processData()
    sample.stop(responseTimer) // записываем время
    call.respond(result)
}

5. Метки (tags) для детализации

Prometheus позволяет добавлять метки (labels) к метрикам. Это полезно для фильтрации данных, например, по HTTP-методу или статусу ответа.

val counterWithTags = Counter
    .builder("app.requests.by.method")
    .tags("method", "GET", "endpoint", "/api/data")
    .register(prometheusRegistry                    

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