
Collecte et exposition de métriques (Micrometer)
Apprenez comment Spring Boot Actuator et Micrometer collectent automatiquement des métriques clés et comment créer et exposer vos propres métriques personnalisées.
Micrometer : Le coeur de la collecte de métriques dans Spring Boot
Au coeur de la capacité de Spring Boot Actuator à gérer les métriques se trouve Micrometer. Micrometer est une bibliothèque d'instrumentation applicative qui agit comme une façade neutre vis-à-vis des systèmes de monitoring. Pensez-y comme SLF4J, mais pour les métriques : vous codez contre l'API de Micrometer, et celui-ci se charge de traduire et d'exposer les métriques dans le format attendu par le système de monitoring de votre choix (Prometheus, Datadog, Graphite, InfluxDB, etc.).
Depuis Spring Boot 2.0, Micrometer est la solution de métriques intégrée par défaut. Lorsque vous incluez le starter `spring-boot-starter-actuator`, Micrometer est automatiquement ajouté à votre projet. Il commence immédiatement à collecter un ensemble riche de métriques standard sans nécessiter de configuration supplémentaire de votre part.
Cette approche par façade découple votre code d'instrumentation du système de monitoring cible. Vous pouvez ainsi changer de système de monitoring en modifiant simplement une dépendance et quelques configurations, sans avoir à réécrire tout le code qui enregistre les métriques.
Métriques collectées automatiquement
L'un des grands avantages de l'intégration Actuator/Micrometer est la quantité de métriques utiles collectées automatiquement. Dès que le starter Actuator est présent, Micrometer instrumente divers aspects de votre application et de son environnement :
- Métriques JVM : Utilisation de la mémoire (heap, non-heap, pools spécifiques), activité du Garbage Collector (pauses, collections), utilisation des threads (nombre, états), classes chargées/déchargées.
- Métriques Système : Utilisation du CPU (par le processus et par le système), mémoire système, nombre de processeurs.
- Métriques du serveur web : Pour les serveurs embarqués supportés (Tomcat, Jetty, Undertow, Netty), Micrometer collecte le nombre de requêtes, leur latence, et le nombre d'erreurs, souvent avec des tags pour l'URI, la méthode HTTP et le statut de la réponse.
- Métriques Spring MVC / WebFlux : Statistiques similaires aux métriques du serveur web, mais au niveau du framework Spring lui-même.
- Métriques de Logging : Nombre d'événements loggés par niveau (pour Logback et Log4j2).
- Métriques de DataSource : Si vous utilisez un pool de connexions supporté (comme HikariCP par défaut), Micrometer rapporte le nombre de connexions actives, inactives, en attente, et le temps d'acquisition.
- Métriques de Cache : Taux de succès (hit ratio), nombre de mises en cache (puts), d'évictions pour les caches gérés par Spring.
- Métriques de Tâches Planifiées et Exécuteurs : Statistiques sur les pools de threads (`ExecutorService`).
Cette instrumentation automatique fournit une base solide pour comprendre la performance et l'utilisation des ressources de votre application sans écrire une seule ligne de code d'instrumentation spécifique.
Explorer les métriques via `/actuator/metrics`
Comme mentionné précédemment, l'endpoint `/actuator/metrics` est le point d'accès de base pour visualiser les métriques collectées. Il permet de lister tous les noms de métriques disponibles et de consulter les détails (valeur, description, tags) d'une métrique spécifique.
Par exemple, pour voir les détails des requêtes HTTP gérées par le serveur :
curl http://localhost:8080/actuator/metrics/http.server.requests
La réponse pourrait ressembler à ceci :
{
"name": "http.server.requests",
"description": "Timer of requests processed by the server",
"baseUnit": "seconds",
"measurements": [
{ "statistic": "COUNT", "value": 150.0 }, // Nombre total de requêtes
{ "statistic": "TOTAL_TIME", "value": 5.12345 }, // Temps total passé (secondes)
{ "statistic": "MAX", "value": 0.250 } // Temps max d'une requête (secondes)
],
"availableTags": [
{ "tag": "exception", "values": ["None", "IllegalArgumentException"] },
{ "tag": "method", "values": ["GET", "POST"] },
{ "tag": "outcome", "values": ["SUCCESS", "CLIENT_ERROR"] },
{ "tag": "status", "values": ["200", "201", "400"] },
{ "tag": "uri", "values": ["/api/products/{id}", "/api/products", "/actuator/health"] }
]
}
Les `availableTags` sont cruciaux. Ils représentent les dimensions selon lesquelles vous pouvez découper ou filtrer cette métrique. Par exemple, vous pourriez demander les métriques uniquement pour les requêtes POST vers `/api/products` qui ont résulté en un statut 201.
Créer des métriques personnalisées avec Micrometer
Bien que les métriques auto-configurées soient utiles, vous aurez souvent besoin de suivre des indicateurs spécifiques à votre domaine métier ou à la logique interne de votre application. Micrometer fournit une API simple pour créer et enregistrer vos propres métriques.
La première étape est d'injecter le `MeterRegistry` dans votre bean Spring (Service, Component, etc.). C'est le registre central où toutes les métriques sont enregistrées.
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Service;
import java.util.concurrent.atomic.AtomicInteger;
@Service
public class OrderService {
private final MeterRegistry meterRegistry;
private final Counter ordersPlacedCounter;
private final AtomicInteger pendingOrders; // Pour un Gauge
public OrderService(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
// 1. Compteur (Counter): Incrémenté à chaque commande
this.ordersPlacedCounter = Counter.builder("orders.placed")
.description("Number of orders placed")
.tag("region", "emea") // Les tags ajoutent des dimensions
.register(meterRegistry);
// 2. Jauge (Gauge): Mesure une valeur actuelle (ex: nb commandes en attente)
// Utilise une référence (ici AtomicInteger) pour obtenir la valeur dynamiquement.
this.pendingOrders = meterRegistry.gauge("orders.pending",
Tags.of("type", "priority"), // Peut aussi utiliser Tags.of()
new AtomicInteger(0));
// Retourne la référence qui sera interrogée pour la valeur
}
public void placeOrder(Order order) {
// 3. Temporisateur (Timer): Mesure la durée et le nombre d'appels d'une opération
Timer.Sample sample = Timer.start(meterRegistry);
try {
// ... logique de traitement de la commande ...
System.out.println("Processing order: " + order.getId());
Thread.sleep(50 + (long)(Math.random() * 100)); // Simulation
this.ordersPlacedCounter.increment(); // Incrémente le compteur
this.pendingOrders.incrementAndGet(); // Met à jour la valeur pour le Gauge
// Simule la fin du traitement
if (Math.random() > 0.1) { // 90% de succès
pendingOrders.decrementAndGet();
} else {
//throw new RuntimeException("Failed to process order");
}
// Arrête le timer et enregistre la durée avec succès
sample.stop(meterRegistry.timer("orders.processing.time", "region", "emea", "status", "success"));
} catch (Exception e) {
// Arrête le timer et enregistre la durée avec échec
sample.stop(meterRegistry.timer("orders.processing.time", "region", "emea", "status", "failure"));
throw new RuntimeException("Order processing failed", e);
}
}
// 4. DistributionSummary: Pour enregistrer la distribution des tailles (ex: taille commande)
public void recordOrderSize(double size) {
meterRegistry.summary("orders.size", "region", "emea")
.record(size);
}
}
Micrometer propose plusieurs types de compteurs :
- `Counter` : Pour compter des événements. Sa valeur ne peut qu'augmenter (ou rester stable). Utile pour : nombre de requêtes, nombre d'erreurs, nombre d'items traités.
- `Gauge` : Pour mesurer une valeur qui peut monter et descendre. La valeur est échantillonnée à intervalles réguliers. Utile pour : taille d'une file d'attente, nombre d'utilisateurs connectés, température actuelle, niveau de mémoire.
- `Timer` : Pour mesurer la durée d'événements courts et leur fréquence. Enregistre à la fois le nombre d'occurrences et la durée totale/moyenne/maximale. Utile pour : temps de réponse des requêtes, durée d'exécution d'une tâche.
- `DistributionSummary` : Pour suivre la distribution statistique d'événements non liés au temps (comme la taille des requêtes/réponses). Enregistre le nombre, la somme totale et la valeur maximale.
L'utilisation judicieuse des tags est essentielle pour ajouter des dimensions à vos métriques, permettant des filtrages et des regroupements puissants dans votre système de monitoring (par région, par type de client, par statut, etc.).
Exposition des métriques pour les systèmes de monitoring
Si l'endpoint `/actuator/metrics` est pratique pour l'exploration, il n'est généralement pas le format idéal pour les systèmes de monitoring automatisés comme Prometheus ou Datadog. Micrometer brille ici en fournissant des modules spécifiques pour chaque système majeur.
Pour exposer les métriques au format Prometheus, par exemple, il suffit d'ajouter la dépendance `micrometer-registry-prometheus` :
io.micrometer
micrometer-registry-prometheus
Une fois cette dépendance présente, Spring Boot Actuator détecte automatiquement le registre Prometheus et expose un nouvel endpoint, typiquement `/actuator/prometheus`. Cet endpoint renvoie les métriques dans le format texte spécifique attendu par Prometheus, prêt à être 'scrapé' (collecté périodiquement) par un serveur Prometheus.
Le processus est similaire pour d'autres systèmes. Par exemple, pour Datadog, vous ajouteriez `micrometer-registry-datadog` et configureriez les propriétés nécessaires (comme la clé API Datadog) dans `application.properties`. Micrometer se chargerait alors de 'pousser' les métriques vers l'API de Datadog à intervalles réguliers.
Cette flexibilité permet aux équipes d'utiliser les outils de monitoring avec lesquels elles sont familières, tout en bénéficiant de l'instrumentation riche et standardisée fournie par Spring Boot et Micrometer. La configuration de base se résume souvent à ajouter la bonne dépendance de registre Micrometer et quelques propriétés de configuration spécifiques au système cible.