Introduction : Pourquoi la surveillance est la base de la stabilité en production
\n\nDans le développement moderne, écrire du code n'est que la moitié du travail. Pour qu'une application Kotlin fonctionne de manière stable sous charge, il est essentiel de comprendre son état interne. Les logs de base et les health checks ne donnent qu'une image superficielle. La surveillance avancée avec des métriques et des alertes permet non seulement de détecter les pannes, mais aussi de les prédire, d'identifier les goulots d'étranglement et de réagir rapidement aux anomalies. Dans cet article, nous allons voir comment construire un système de surveillance prêt pour la production pour les applications Kotlin avec la stack Micrometer + Prometheus + Alertmanager + Grafana.\n
\n\n1. Collecte de métriques avec Micrometer et Prometheus
\n\nMicrometer est une façade pour la collecte de métriques, devenue de facto la norme dans l'écosystème JVM et Kotlin. Elle prend en charge de nombreux backends : Prometheus, Datadog, New Relic, etc. Pour les applications Kotlin (Spring Boot, Ktor, http4k), l'intégration est triviale.\n
\n\n1.1. Ajout et configuration
\nAjoutez les dépendances nécessaires dans build.gradle.kts :
// Pour Spring Boot\nimplementation("io.micrometer:micrometer-registry-prometheus")\n\n// Pour Ktor (configuration manuelle)\nimplementation("io.micrometer:micrometer-core:1.12.0")\nimplementation("io.micrometer:micrometer-registry-prometheus:1.12.0")\n\nPour Spring Boot, un bean MeterRegistry est créé automatiquement. Dans Ktor, vous devez l'initialiser manuellement :
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// Exposition du point d'accès /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étriques personnalisées
\nEn plus des métriques standard (JVM, CPU, mémoire), ajoutez des métriques métier. Exemple d'un compteur de commandes traitées :
\nval orderCounter = Counter.builder("orders.processed")\n .description("Total processed orders")\n .register(registry)\n\nfun processOrder(order: Order) {\n // logique métier\n orderCounter.increment()\n}\n\nOu un histogramme pour le temps d'exécution d'une requête :
\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. Alertes avancées : des seuils aux prédictions
\n\nLes alertes basées sur des seuils simples (ex. CPU > 90%) génèrent souvent de fausses alertes. À un niveau avancé, nous utilisons Alertmanager et des règles PromQL avec agrégation et prédiction.\n
\n\n2.1. Configuration d'Alertmanager
\nConfiguration de alertmanager.yml pour envoyer des notifications vers Telegram et 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. Règles PromQL pour des alertes intelligentes
\nDans rules.yml, décrivons une règle qui se déclenche si le 95e percentile du temps de réponse dépasse 500 ms pendant 5 minutes :
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