Introdução: Por que o monitoramento é a base da estabilidade em produção
\n\nNo desenvolvimento moderno, escrever código é apenas metade do trabalho. Para que uma aplicação em Kotlin funcione de forma estável sob carga, é necessário entender seu estado interno. Logs básicos e health checks fornecem apenas uma visão superficial. O monitoramento avançado com métricas e alertas permite não apenas detectar falhas, mas prevê-las, identificar gargalos e reagir rapidamente a anomalias. Neste artigo, vamos abordar como construir um sistema de monitoramento pronto para produção para aplicações Kotlin com a stack Micrometer + Prometheus + Alertmanager + Grafana.\n
\n\n1. Coleta de métricas com Micrometer e Prometheus
\n\nMicrometer é um facade para coleta de métricas que se tornou o padrão de facto no mundo JVM e Kotlin. Ele suporta diversos backends: Prometheus, Datadog, New Relic e outros. Para aplicações Kotlin (Spring Boot, Ktor, http4k), a integração é trivial.\n
\n\n1.1. Conexão e configuração
\nAdicione as dependências necessárias no build.gradle.kts:
// Para Spring Boot\nimplementation("io.micrometer:micrometer-registry-prometheus")\n\n// Para Ktor (configuração manual)\nimplementation("io.micrometer:micrometer-core:1.12.0")\nimplementation("io.micrometer:micrometer-registry-prometheus:1.12.0")\n\nPara Spring Boot, um bean MeterRegistry é criado automaticamente. No Ktor, você precisa inicializá-lo manualmente:
import io.micrometer.prometheus.PrometheusMeterRegistry\nimport io.micrometer.core.instrument.Clock\nimport io.prometheus.client.CollectorRegistry\n\nval registry = PrometheusMeterRegistry(\n PrometheusConfig.DEFAULT,\n CollectorRegistry.defaultRegistry,\n Clock.SYSTEM\n)\n\n// Exportar endpoint /metrics\nembeddedServer(Netty, port = 8080) {\n routing {\n get("/metrics") {\n call.respondText(registry.scrape())\n }\n }\n}.start(wait = true)\n\n1.2. Métricas personalizadas
\nAlém das métricas padrão (JVM, CPU, memória), adicione métricas de negócio. Exemplo de um contador de pedidos processados:
\nval orderCounter = Counter.builder("orders.processed")\n .description("Total de pedidos processados")\n .register(registry)\n\nfun processOrder(order: Order) {\n // lógica de negócio\n orderCounter.increment()\n}\n\nOu um histograma para o tempo de execução da requisição:
\nval requestTimer = Timer.builder("http.requests.duration")\n .description("Duração das requisições HTTP")\n .publishPercentiles(0.5, 0.95, 0.99)\n .sla(Duration.ofMillis(100), Duration.ofMillis(500))\n .register(registry)\n\nfun handleRequest(block: () -> Response): Response {\n return requestTimer.record(block)\n}\n\n2. Alertas avançados: de valores limite a previsões
\n\nAlertas baseados em limites simples (ex: CPU > 90%) frequentemente geram falsos positivos. Em um nível avançado, usamos o Alertmanager e regras PromQL com agregação e previsão.\n
\n\n2.1. Configuração do Alertmanager
\nConfiguração do alertmanager.yml para enviar notificações para Telegram e Slack:
route:\n receiver: 'team-alerts'\n group_wait: 30s\n group_interval: 5m\n repeat_interval: 1h\n\nreceivers:\n- name: 'team-alerts'\n telegram_configs:\n - bot_token: 'YOUR_BOT_TOKEN'\n chat_id: -123456789\n parse_mode: 'HTML'\n slack_configs:\n - api_url: 'https://hooks.slack.com/services/...'\n channel: '#alerts'\n\n2.2. Regras PromQL para alertas inteligentes
\nNo rules.yml, descrevemos uma regra que dispara se o percentil 95 do tempo de resposta exceder 500 ms por 5 minutos:
groups:\n- name: http_latency\n rules:\n - alert: HighLatencyP95\n expr: |\n histogram_quantile(0.95,\n sum(rate(http_requests_duration_seconds_bucket[5m])) by (le, endpoint)\n ) > 0.5\n for: 5m\n ann