Surveiller un microservice MicroProfile avec Prometheus et Grafana

Faisant partie de MicroProfile, l'API Metrics for Eclipse MicroProfile permet à un service REST Java/Jakarta EE d'exposer facilement des métriques, pouvant alors être exploitées à des fins de surveillance ; par défaut, on aura des mesures relatives à l'environnement d'exécution, tandis que l'on pourra également ajouter ses propres mesures au moyen d'annotations proposées par l'API Metrics.

Microservice microprofile-metrics

Cet article sera illustré par le projet microprofile-metrics, accessible sur Bitbucket : il s'agit d'un microservice que vous pouvez construire avec Maven, et ayant une dépendance à MicroProfile 2.2.
microprofile-metrics a été testée avec Payara Micro, et une fois déployée sur votre machine, l'application expose les deux points de terminaison suivants, par le service REST HelloWorldResource :

Ces deux URL correspondent respectivement aux méthodes sayHello() et timedRequest() de la ressource HelloWorldResource, sur lesquelles on a également appliqué une annotation de l'API Metrics.

La page d'accueil du microservice vous permettra d'ailleurs de déclencher l'exécution de ces méthodes, ainsi que d'accéder aux métriques.

Intéressons-nous à l'annotation @Counted sur la méthode sayHello() :

1
2
3
4
5
6
@Counted(name = "sayHelloCounted",
    absolute = true,
    monotonic = true,
    displayName = "SayHello Count",
    description = "Metrics to show how many times sayHello method was called",
    tags = {"say=hello"})

Cette annotation permet de compter le nombre d'appels faits à la méthode sayHello().

L'ensemble des métriques du serveur d'applications, et pas uniquement de notre microservice, est disponible via l'URL http://localhost:8080/metrics, par défaut au format Prometheus, qui est une solution open source de collecte de métriques et de supervision.
Pour connaître le nombre d'appels à notre méthode, à condition de l'avoir appelée au moins une fois, il suffit d'envoyer une requête HTTP de type GET vers l'URL suivante :

http://localhost:8080/metrics/application/sayHelloCounted

La réponse vient par défaut dans le format Prometheus, mais il est possible de la demander au format JSON, en utilisant le paramètre d'entête HTTP Accept avec la valeur application/json ; dans ce cas, nous aurions la réponse suivante :

1
2
3
{
    "sayHelloCounted": 3
}

On peut également demander les métadonnées liés à notre compteur, en émettant une requête HTTP sur la même URL, mais de type OPTIONS ; dans le format JSON, le serveur répond ceci :

1
2
3
4
5
6
7
8
9
10
{
    "sayHelloCounted": {
        "name": "sayHelloCounted",
        "displayName": "SayHello Count",
        "description": "Metrics to show how many times sayHello method was called",
        "type": "counter",
        "unit": "none",
        "tags": "say=hello"
    }
}

Par convention, notre métrique qui est un compteur nommé sayHelloCounted, se situe dans la portée application, et il existe d'autres métrique associés aux portées base (métriques de base du serveur) et vendor (métriques spécifiques à l'éditeur du serveur d'applications).

Prometheus

Si vous exécutez un serveur Prometheus, dans son fichier de configuration prometheus.yml, il vous faut définir un job indiquant notamment sur quelle URL récupérer les métriques de notre microservice.
Dans l'exemple de fichier de configuration suivant, le job mp-metrics indique de récupérer les données sur l'URL http://192.168.99.100:8080/metrics (dans la configuration, le protocole http et le chemin /metrics sont implicites).
Un autre job, nommé prometheus permet à Prometheus de se surveiller lui-même.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.

scrape_configs:
  - job_name: 'prometheus'

    # Override the global default and scrape targets from this job every 5 seconds.
    scrape_interval: 5s

    static_configs:
      - targets: ['localhost:9090']
      
  - job_name: 'mp-metrics'
    static_configs:
      - targets: ['192.168.99.100:8080']

Note : cette configuration est donnée à titre d'exemple, et je l'ai utilisée dans un conteneur Docker d'image prom/prometheus ; c'est la raison pour laquelle localhost fait ici référence au serveur Prometheus, et 192.168.99.100 à l'hôte exécutant le microservice microprofile-metrics.

Avec le serveur Prometheus en exécution, la page Targets (élément de menu Targets sous le menu Status), devrait vous présenter les cibles à partir desquelles les métriques sont collectées.

Tandis que Prometheus collecte les données, vous pouvez demander la valeur d'une métrique dans la page Graph de l'interface utilisateur, ou afficher un graphe des valeurs en fonction du temps, comme ci-dessous, pour notre compteur identifié par application:say_hello_counted :

Grafana

Le meilleur ami de Prometheus est Grafana : ce projet open source offre la possibilité de créer et d'exposer de jolis tableaux de bords, alimentés en données par des sources de données variées comme celle de Prometheus.
La capture d'écran ci-dessous montre que l'on a ajouté notre serveur Prometheus comme source de données, dans la configuration d'une instance de Grafana :

Il est assez simple de créer un graghe de type Singlestat dans le seul but d'afficher la valeur de notre compteur, en stipulant dans l'onglet Metrics, une requête de valeur application:say_hello_counted (exactement ce qui a été utilisé dans Prometheus) :

La capture d'écran ci-dessous présente le tableau de bord SayHello Metric, dans lequel on agrégé deux graphes, le premier donnant la valeur actuelle de notre compteur, le second, son évolution au cours des 30 dernières minutes :

Comme pour Prometheus, par simplification, vous pouvez aussi avoir recours à un conteneur Docker utilisant l'image grafana/grafana pour exécuter Grafana.

Grafana est très riche et mérite que l'on s'y attarde pour concevoir des tableaux beaucoup plus complets et utiles, à partir de métriques issues de différents microservices.
Maintenant, c'est à vous de tirer parti des métriques que peut exposer un microservice avec une dépendance à MicroProfile Metrics !