Prometheus метрики в Kotlin: полное руководство по интеграции
В современной разработке мониторинг и сбор метрик являются критически важными для поддержания стабильности приложений. Prometheus — это ведущая система мониторинга с открытым исходным кодом, которая позволяет собирать, хранить и анализировать данные о производительности. В этой статье мы рассмотрим, как добавить Prometheus метрики в приложения на Kotlin, используя библиотеку Micrometer и настраиваемый HTTP-сервер.
Почему стоит использовать Prometheus с Kotlin?
- Гибкость: Prometheus поддерживает множество типов метрик: счетчики, гистограммы, суммаризации и датчики.
- Встроенная интеграция: Kotlin полностью совместим с Java-экосистемой, что позволяет использовать Micrometer — популярный инструмент для сбора метрик.
- Масштабируемость: Prometheus легко масштабируется для мониторинга микросервисов и распределенных систем.
Настройка проекта с Gradle
Для начала добавьте зависимости в файл build.gradle.kts:
dependencies {
implementation("io.micrometer:micrometer-core:1.12.0")
implementation("io.micrometer:micrometer-registry-prometheus:1.12.0")
// Для HTTP-сервера (используем Ktor)
implementation("io.ktor:ktor-server-netty:2.3.7")
implementation("io.ktor:ktor-server-content-negotiation:2.3.7")
}
Создание Prometheus-регистратора
Основой сбора метрик является PrometheusMeterRegistry. Создайте его в вашем приложении:
import io.micrometer.prometheus.PrometheusConfig
import io.micrometer.prometheus.PrometheusMeterRegistry
val registry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
Определение метрик
Рассмотрим три основных типа метрик:
- Counter — счетчик, который только увеличивается (например, количество запросов).
- Gauge — текущее значение (например, количество активных пользователей).
- Timer — время выполнения операций.
Пример создания метрик:
import io.micrometer.core.instrument.Counter
import io.micrometer.core.instrument.Gauge
import io.micrometer.core.instrument.Timer
val requestCounter: Counter = Counter
.builder("api.requests.total")
.description("Общее количество запросов к API")
.register(registry)
val activeUsersGauge: Gauge = Gauge
.builder("app.users.active")
.description("Количество активных пользователей")
.register(registry) { activeUsersCount }
val requestTimer: Timer = Timer
.builder("api.requests.duration")
.description("Время выполнения запросов")
.register(registry)
var activeUsersCount = 0
Экспорт метрик через HTTP
Чтобы Prometheus мог собирать метрики, их нужно экспортировать в формате /metrics. Используем Ktor для создания эндпоинта:
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import io.ktor.server.routing.get
import io.ktor.server.routing.routing
import io.ktor.server.response.respondText
fun startMetricsServer(port: Int = 9090) {
embeddedServer(Netty, port = port) {
routing {
get("/metrics") {
val scrape = registry.scrape()
call.respondText(scrape, contentType = io.ktor.http.ContentType.Text.Plain)
}
}
}.start(wait = false)
}
Интеграция с бизнес-логикой
Обновляйте метрики в коде вашего приложения:
fun handleRequest() {
requestTimer.record {
// Имитация обработки запроса
Thread.sleep(100)
requestCounter.increment()
}
}
fun userLoggedIn() {
activeUsersCount++
}
fun userLoggedOut() {
activeUsersCount--
}
Полный пример приложения
Соберем всё вместе в одном файле Main.kt:
import io.micrometer.prometheus.PrometheusConfig
import io.micrometer.prometheus.PrometheusMeterRegistry
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import io.ktor.server.routing.get
import io.ktor.server.routing.routing
import io.ktor.server.response.respondText
import io.micrometer.core.instrument.Counter
import io.micrometer.core.instrument.Timer
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
val registry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
val requestCounter = Counter
.builder("app.requests.total")
.description("Total API requests")
.register(registry)
val requestTimer = Timer
.builder("app.requests.duration")
.description("Request duration")
.register(registry)
fun main() {
// Запуск HTTP-серве