Мониторинг Kotlin приложений: метрики и алерты продвинутого уровня
В современной разработке программного обеспечения мониторинг перестал быть опцией — это обязательный элемент production-инфраструктуры. Для Kotlin-приложений, работающих под высокой нагрузкой, недостаточно простого логирования. Требуется полноценная observability: сбор метрик, настройка алертов и визуализация данных в реальном времени. В этой статье мы разберем продвинутые техники мониторинга Kotlin-приложений с использованием стека Prometheus, Grafana и Micrometer.
1. Инструментарий: Micrometer и Prometheus
Лучший способ внедрить мониторинг в Kotlin-приложение — использовать библиотеку Micrometer. Она предоставляет фасад для различных систем мониторинга, включая Prometheus. Micrometer поддерживает как JVM-метрики, так и кастомные бизнес-показатели.
Подключим зависимости в build.gradle.kts:
dependencies {
implementation("io.micrometer:micrometer-core:1.12.0")
implementation("io.micrometer:micrometer-registry-prometheus:1.12.0")
implementation("io.ktor:ktor-server-metrics-micrometer:2.3.7")
}
Для Ktor-приложения настройка выглядит так:
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.application.*
import io.ktor.server.metrics.micrometer.*
import io.micrometer.prometheus.PrometheusMeterRegistry
import io.micrometer.prometheus.PrometheusConfig
fun main() {
val meterRegistry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
embeddedServer(Netty, port = 8080) {
install(MicrometerMetrics) {
registry = meterRegistry
// Добавляем стандартные метрики JVM
meterRegistry.config().commonTags("application", "my-kotlin-app")
}
routing {
get("/metrics") {
call.respond(meterRegistry.scrape())
}
}
}.start(wait = true)
}
Этот код автоматически собирает метрики HTTP-запросов, пула потоков и JVM. Эндпоинт /metrics отдаёт данные в формате Prometheus.
2. Кастомные метрики: бизнес-показатели
Стандартных метрик часто недостаточно. Для продвинутого мониторинга нужно собирать бизнес-показатели: количество заказов, время обработки платежей, частоту ошибок валидации.
Пример создания кастомного счётчика и таймера:
import io.micrometer.core.instrument.Counter
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Timer
import java.util.concurrent.TimeUnit
class OrderMetrics(private val registry: MeterRegistry) {
private val orderCounter: Counter = Counter.builder("orders.created")
.description("Total number of created orders")
.register(registry)
private val processTimer: Timer = Timer.builder("orders.processing.time")
.description("Time to process an order")
.publishPercentiles(0.5, 0.95, 0.99)
.register(registry)
fun recordOrderCreation() {
orderCounter.increment()
}
fun measureProcessingTime(block: () -> Unit) {
processTimer.record(block)
}
}
Использование в сервисе:
class OrderService(private val metrics: OrderMetrics) {
fun createOrder(order: Order): Order {
metrics.recordOrderCreation()
return metrics.measureProcessingTime {
// бизнес-логика
Thread.sleep(100) // симуляция
order
}
}
}
Обратите внимание на перцентили: они позволяют отслеживать не только среднее время, но и "хвосты" (p99), что критично для SLA.
3. Настройка алертов в Prometheus
Сбор метрик бесполезен без системы оповещения. Алерты настраиваются в конфигурации Prometheus (файл alert.rules.yml).
Пример правил для Kotlin-приложения:
groups:
- name: kotlin_app_alerts
rules:
- alert: HighErrorRate
expr: rate(http_server_requests_seconds_count{status=~"5.."}[5m]) / rate(http_server_requests_seconds_count[5m]) > 0.05
for: 2m
labels:
severity: critical
annotations:
summary: "High HTTP 5xx error rate ({{ $value | humanizePercentage }})"
- alert: SlowResponses
expr: histogram_quantile(0.95, rate(http_server_requests_seconds_bucket[5m])) > 2
for: 1m
labels:
severity: warning
annotations:
summary: "P95 response time is {{ $value }} seconds"
- alert: HighHeapUsage
expr: jvm_memory_used_bytes{area="heap"} / jvm_memory_max_bytes{area="heap"} > 0.85
for: 5m
labels:
severity: warning
annotations:
summary: "JVM heap usage > 85%"
Эти правила срабатывают при превышении порогов: более 5% ошибок 5xx, p95 ответа дольше 2 секунд, заполнение кучи более 85%.
Для отправки уведомлений используется Alertmanager. Пример конфигурации для Telegram:
receivers:
- name: 'telegram'
telegram_configs:
- bot_token: 'YOUR_BOT_TOKEN'
chat_id: 123456789
parse_mode: 'HTML'
route:
receiver: 'telegram'
group_by: ['alertname', 'severity']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
4. Визуализация в Grafana: продвинутые дашборды
Grafana позволяет создавать сложные дашборды. Для Kotlin-приложения рекомендую включить следующие панели:
- RPS и Latency — график запросов в секунду с разбивкой по статусам (2xx, 4xx, 5xx) и p50/p95/p99 latency.
- JVM Metrics — heap usage, GC pauses, количество потоков, CPU usage.
- Бизнес-метрики — кастомные счётчики и таймеры, например "заказы в минуту" или "время обработки платежа".
- Алерты — статус активных алертов, история срабатываний.
Пример PromQL-запроса для панели "P95 latency":
histogram_quantile(0.95,
sum(rate(http_server_requests_seconds_bucket[5m])) by (le, uri)
)
Для отображения да