Contactez-nous

Vérifications de santé (`HealthIndicator` personnalisés)

Apprenez à implémenter des HealthIndicator personnalisés pour intégrer l'état de santé de vos propres composants applicatifs à l'endpoint /health de Spring Boot Actuator.

Pourquoi créer des indicateurs de santé personnalisés ?

L'endpoint /actuator/health de Spring Boot Actuator est un outil essentiel pour surveiller l'état de santé global d'une application. Par défaut, il agrège les résultats de plusieurs indicateurs de santé (HealthIndicator) auto-configurés par Spring Boot, vérifiant l'état de composants clés comme la base de données, l'espace disque, les brokers de messages (RabbitMQ, Kafka), etc.

Cependant, l'état de santé de votre application ne dépend pas uniquement de ces composants standards. Vous pouvez avoir des services externes critiques, des caches spécifiques, des files d'attente internes, ou d'autres ressources vitales dont le bon fonctionnement est essentiel. Si l'un de ces composants personnalisés tombe en panne, votre application peut être considérée comme dégradée ou hors service, même si la base de données et l'espace disque sont opérationnels.

C'est là qu'interviennent les HealthIndicator personnalisés. En implémentant cette interface, vous pouvez créer vos propres vérifications de santé pour n'importe quel aspect de votre application et les intégrer de manière transparente à l'endpoint /actuator/health. Cela permet d'obtenir une vision beaucoup plus précise et pertinente de l'état de santé réel de votre application du point de vue métier ou technique spécifique.

Implémenter l'interface `HealthIndicator`

La création d'un indicateur de santé personnalisé est simple. Il suffit d'implémenter l'interface org.springframework.boot.actuate.health.HealthIndicator. Cette interface ne définit qu'une seule méthode : Health health().

La méthode health() doit retourner un objet Health. Cet objet encapsule le résultat de la vérification de santé. Il est construit à l'aide d'un builder et contient principalement deux informations :

  • Le statut (Status) : Indique l'état du composant vérifié. Les statuts prédéfinis les plus courants sont Status.UP (fonctionnel), Status.DOWN (en panne), Status.OUT_OF_SERVICE (temporairement indisponible), et Status.UNKNOWN (état indéterminé). Le statut global de l'endpoint /health est déterminé par une agrégation des statuts de tous les indicateurs (par défaut, si un seul est DOWN, le statut global est DOWN).
  • Les détails (details) : Une map (Map) contenant des informations supplémentaires sur l'état du composant. Ces détails sont affichés dans la réponse de /health lorsque la propriété management.endpoint.health.show-details est configurée de manière appropriée (when-authorized ou always).

Pour que votre implémentation soit découverte et utilisée par Actuator, il suffit généralement de la déclarer comme un bean Spring, par exemple en l'annotant avec @Component.

Exemple : Vérifier un service externe

Imaginons que notre application dépende d'un service externe "Service Météo" accessible via une API REST. Nous voulons créer un HealthIndicator pour vérifier si ce service est joignable et répond correctement.

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

@Component // Déclare ce composant comme un bean Spring
public class ServiceMeteoHealthIndicator implements HealthIndicator {

    private final RestTemplate restTemplate;
    private final String serviceUrl = "https://api.example-meteo.com/ping"; // URL de test du service

    public ServiceMeteoHealthIndicator() {
        // Idéalement, injecter un RestTemplate configuré via @Autowired
        this.restTemplate = new RestTemplate();
    }

    @Override
    public Health health() {
        try {
            // Tente d'appeler une URL simple du service externe
            restTemplate.getForObject(serviceUrl, String.class);
            // Si l'appel réussit sans exception, le service est UP
            return Health.up()
                       .withDetail("service", "Service Météo")
                       .withDetail("url", serviceUrl)
                       .build();
        } catch (RestClientException e) {
            // Si une exception se produit (timeout, erreur 4xx/5xx, etc.), le service est DOWN
            return Health.down()
                       .withDetail("service", "Service Météo")
                       .withDetail("url", serviceUrl)
                       .withDetail("error", e.getMessage()) // Ajoute le message d'erreur aux détails
                       .build();
        } catch (Exception e) {
            // Gérer d'autres exceptions potentielles
             return Health.down(e)
                       .withDetail("service", "Service Météo")
                       .withDetail("url", serviceUrl)
                       .build();
        }
    }
}

Dans cet exemple :

  • La classe implémente HealthIndicator.
  • Elle est annotée @Component pour être détectée par Spring.
  • La méthode health() essaie d'appeler une URL du service externe.
  • Si l'appel réussit, elle retourne Health.up() avec des détails informatifs.
  • Si une RestClientException (ou autre) survient, elle retourne Health.down(), incluant le message d'erreur dans les détails pour faciliter le diagnostic.
  • Le constructeur Health.down(Exception e) est une alternative qui inclut automatiquement les détails de l'exception.

Intégration dans l'endpoint /health

Une fois votre HealthIndicator personnalisé déclaré comme bean, Actuator l'inclura automatiquement dans l'agrégation de l'endpoint /actuator/health. Le nom du bean (par défaut, le nom de la classe avec la première lettre en minuscule, ici `serviceMeteoHealthIndicator`) est utilisé comme clé dans la réponse JSON, mais sans le suffixe `HealthIndicator`.

Si notre `ServiceMeteoHealthIndicator` retourne UP, et en supposant que show-details est activé, la réponse de /actuator/health pourrait ressembler à ceci :

{
  "status": "UP",
  "components": {
    "db": { /* ... détails base de données ... */ },
    "diskSpace": { /* ... détails espace disque ... */ },
    "serviceMeteo": {  // Note: 'HealthIndicator' est retiré du nom
      "status": "UP",
      "details": {
        "service": "Service Météo",
        "url": "https://api.example-meteo.com/ping"
      }
    }
    /* ... autres indicateurs ... */
  }
}

Si le service météo était en panne, le statut de `serviceMeteo` serait DOWN, des détails d'erreur seraient présents, et le statut global de l'application pourrait passer à DOWN (selon la configuration d'agrégation et les autres indicateurs).

Indicateurs composites et autres considérations

Pour des scénarios plus complexes, vous pouvez regrouper plusieurs indicateurs logiquement liés en implémentant CompositeHealthContributor au lieu de HealthIndicator. Cela permet de créer une structure hiérarchique dans la réponse de l'endpoint /health.

Si vous travaillez avec des applications réactives (Spring WebFlux), vous devriez implémenter l'interface ReactiveHealthIndicator. Sa méthode health() retourne un Mono, s'intégrant naturellement dans les flux réactifs.

Bonnes pratiques pour les Health Indicators :

  • Rapidité : Les vérifications de santé doivent être rapides pour ne pas ralentir l'endpoint /health, qui peut être appelé fréquemment par les systèmes de monitoring. Evitez les opérations longues ou coûteuses.
  • Robustesse : Gérez correctement les exceptions au sein de la méthode health() pour toujours retourner un objet Health valide, même en cas d'erreur lors de la vérification.
  • Pertinence des détails : Fournissez des détails utiles pour le diagnostic, mais évitez d'exposer des informations trop sensibles (comme des mots de passe ou des données confidentielles).
  • Timeout : Si vous appelez des services externes, configurez des timeouts raisonnables pour éviter que l'indicateur ne bloque indéfiniment.

En ajoutant des HealthIndicator personnalisés, vous enrichissez considérablement la capacité de surveillance de votre application Spring Boot, permettant une détection plus rapide et plus précise des problèmes spécifiques à votre domaine ou à votre infrastructure.