Introducción: Por qué el monitoreo es la base de la estabilidad en producción
\n\nEn el desarrollo moderno, escribir código es solo la mitad del trabajo. Para que una aplicación en Kotlin funcione de manera estable bajo carga, es necesario comprender su estado interno. Los registros básicos y las comprobaciones de salud solo brindan una visión superficial. El monitoreo avanzado con métricas y alertas permite no solo detectar fallos, sino predecirlos, identificar cuellos de botella y reaccionar rápidamente ante anomalías. En este artículo, analizaremos cómo construir un sistema de monitoreo listo para producción para aplicaciones Kotlin basado en el stack Micrometer + Prometheus + Alertmanager + Grafana.\n
\n\n1. Recopilación de métricas con Micrometer y Prometheus
\n\nMicrometer es una fachada para la recopilación de métricas que se ha convertido en el estándar de facto en el mundo JVM y Kotlin. Admite múltiples backends: Prometheus, Datadog, New Relic y otros. Para aplicaciones Kotlin (Spring Boot, Ktor, http4k), la integración es trivial.\n
\n\n1.1. Conexión y configuración
\nAgregue las dependencias necesarias en build.gradle.kts:
// Para Spring Boot\nimplementation("io.micrometer:micrometer-registry-prometheus")\n\n// Para Ktor (configuración manual)\nimplementation("io.micrometer:micrometer-core:1.12.0")\nimplementation("io.micrometer:micrometer-registry-prometheus:1.12.0")\n\nPara Spring Boot, se crea automáticamente un bean MeterRegistry. En Ktor, debe inicializarlo 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
\nAdemás de las estándar (JVM, CPU, memoria), agregue métricas de negocio. Ejemplo de un contador de pedidos procesados:
\nval orderCounter = Counter.builder("orders.processed")\n .description("Total processed orders")\n .register(registry)\n\nfun processOrder(order: Order) {\n // lógica de negocio\n orderCounter.increment()\n}\n\nO un histograma para el tiempo de ejecución de la solicitud:
\nval requestTimer = Timer.builder("http.requests.duration")\n .description("Duration of HTTP requests")\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 avanzadas: de valores umbral a predicciones
\n\nLas alertas basadas en umbrales simples (por ejemplo, CPU > 90%) a menudo generan falsos positivos. A nivel avanzado, utilizamos Alertmanager y reglas PromQL con agregación y predicción.\n
\n\n2.1. Configuración de Alertmanager
\nConfiguración de alertmanager.yml para enviar notificaciones a Telegram y 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. Reglas PromQL para alertas inteligentes
\nEn rules.yml describamos una regla que se activa si el percentil 95 del tiempo de respuesta supera los 500 ms durante 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