Retour au cours

infra / monitoring-observabilite

PromQL de base

Leçon 41 exercice

Explication

Ce que vous allez apprendre

  • Filtrer des séries temporelles par label, y compris avec des expressions régulières
  • Comprendre la différence entre un vecteur instantané et un vecteur de plage ([5m])
  • Utiliser rate() pour transformer un compteur cumulatif en débit exploitable
  • Agréger des métriques par dimension avec sum(...) by (...)
  • Calculer un taux d'erreur et un percentile de latence, les deux requêtes les plus utilisées en dashboard

Dans quel contexte ?

mon-api expose désormais ses métriques (leçon précédente), mais un chiffre brut comme http_requests_total{status="500"} = 1204 ne dit rien d'utile en soi : 1204 erreurs en un an n'a rien à voir avec 1204 erreurs en 5 minutes. Il faut un langage pour transformer ces compteurs bruts en informations exploitables — c'est exactement le rôle de PromQL.

D'abord, la forme la plus simple d'une requête

Taper juste http_requests_total renvoie la valeur actuelle de chaque série correspondant à ce nom de métrique. Pour restreindre le résultat, on ajoute des filtres entre accolades sur les labels, comme http_requests_total{status="500"} pour ne garder que les erreurs serveur.

Ces filtres peuvent aussi utiliser des expressions régulières, avec =~ pour "correspond à" et !~ pour "ne correspond pas à" — très utile pour cibler toute une famille de status codes d'un coup (status=~"5..").

Une fois le filtrage acquis, il reste un problème : un compteur brut ne dit rien sur sa vitesse

http_requests_total continue de grimper indéfiniment tant que l'application tourne. Savoir qu'il vaut "8421" à un instant donné ne renseigne ni sur le trafic actuel ni sur une tendance. Il faut regarder son évolution sur une fenêtre de temps.

C'est là qu'intervient le "range vector" : http_requests_total[5m] récupère toutes les valeurs des 5 dernières minutes plutôt qu'une seule valeur instantanée. Cette syntaxe entre crochets est indispensable pour toute fonction qui calcule un débit.

FonctionRôleExemple
rate()Débit moyen par seconde sur la fenêtrerate(http_requests_total[5m])
increase()Croissance totale sur la fenêtre (pas par seconde)increase(http_requests_total[1h])
sum() by (...)Agrégation groupée par labelsum(rate(...)) by (status)
histogram_quantile()Percentile calculé depuis un Histogramhistogram_quantile(0.95, ...)

Prérequis

Il faut avoir des métriques réellement exposées par une application pour suivre cette leçon efficacement (voir la leçon précédente sur l'instrumentation) ; les exemples utilisent directement http_requests_total et http_request_duration_seconds_bucket.

rate() est la fonction la plus utilisée de tout PromQL — voici pourquoi

rate(http_requests_total[5m]) convertit ce compteur toujours croissant en "requêtes par seconde" sur les 5 dernières minutes. Elle gère aussi intelligemment les redémarrages de l'application (quand le compteur retombe brutalement à zéro), ce qu'un simple calcul de différence manuel ne ferait pas correctement.

Piège fréquent

N'applique jamais rate() directement sur un Gauge : cette fonction n'a de sens que sur un Counter, qui ne fait qu'augmenter. Sur un Gauge (qui monte et descend), le résultat de rate() serait mathématiquement absurde et trompeur.

Maintenant que tu sais mesurer un débit, il faut apprendre à le regrouper

Sans agrégation, PromQL renvoie une série PAR combinaison de labels, ce qui devient vite illisible dès qu'une métrique a plusieurs dimensions. sum(rate(http_requests_total[5m])) by (status) résout ça : il additionne toutes les séries qui partagent le même status, ne gardant qu'une ligne par valeur de status.

Bonne pratique

Le calcul de taux d'erreur (5xx / total * 100) et le calcul de P95 avec histogram_quantile() reviennent dans quasiment tous les dashboards de production. Mémorise ces deux formules par coeur : elles servent de base à l'alerting comme au reporting.

Le piège à éviter en fin de leçon

Une erreur fréquente est d'oublier que histogram_quantile() s'applique sur le résultat d'un sum(...) by (le) et non directement sur le bucket brut : le label le (less than or equal), créé automatiquement par chaque Histogram, doit être préservé dans le regroupement, sinon la fonction ne peut pas reconstruire la distribution.

Une fois ces bases solides, la leçon suivante va plus loin avec des fonctions PromQL plus avancées : jointures entre métriques, extrapolation et détection d'absence de données.

Commandes & code

PromQL de base

promql
# Requête instantanée : valeur actuelle d'une série
http_requests_total

# Filtrer par label (égalité exacte)
http_requests_total{status="500"}

# Filtrer par plusieurs labels (ET implicite)
http_requests_total{status="500", method="POST"}

# Opérateurs de comparaison sur les labels
http_requests_total{status=~"5.."}      # regex : tous les status 5xx
http_requests_total{status!~"2.."}      # regex négative : tout SAUF les 2xx
http_requests_total{path!="/health"}    # différent de
promql
# range vector : valeurs sur une FENÊTRE de temps (nécessaire pour rate/increase)
http_requests_total[5m]                  # toutes les valeurs des 5 dernières minutes

# rate() : taux de croissance par seconde, calculé sur la fenêtre — LA fonction la plus utilisée
rate(http_requests_total[5m])
# -> convertit un compteur brut en "requêtes par seconde", gère aussi les resets (redémarrage du process)

# increase() : croissance TOTALE sur la fenêtre (pas par seconde)
increase(http_requests_total[1h])        # nombre de requêtes reçues sur la dernière heure
promql
# Agrégations : sum, avg, max, min, count — avec "by" pour grouper, "without" pour exclure des labels
sum(rate(http_requests_total[5m]))                       # débit total, toutes dimensions confondues
sum(rate(http_requests_total[5m])) by (status)             # débit par status code
sum(rate(http_requests_total[5m])) by (method, path)         # débit par méthode ET par route
sum(rate(http_requests_total[5m])) without (instance)          # tout sauf le label "instance"

avg(http_request_duration_seconds) by (path)               # latence moyenne par route
max(node_memory_usage_bytes) by (instance)                    # pic mémoire par serveur
promql
# Combiner plusieurs métriques : taux d'erreur (%) — requête ULTRA classique en dashboard
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
* 100

# Comparer dans le temps avec offset : "il y a 1 semaine" pour détecter une anomalie
rate(http_requests_total[5m]) - rate(http_requests_total[5m] offset 1w)
promql
# Histogram : calculer des percentiles avec histogram_quantile()
histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
# -> latence au 95e percentile (P95) : 95% des requêtes sont plus rapides que cette valeur
# "le" (less than or equal) est le label automatique créé par les buckets d'un Histogram
FonctionUsage
rate()débit par seconde sur un counter (le plus utilisé)
increase()croissance totale sur la fenêtre
sum() by(...)agrégation groupée par label
histogram_quantile()percentiles depuis un Histogram
offsetcomparer avec une période passée

Résumé

  • rate() sur un [5m] est la requête la plus courante : convertit un compteur cumulatif en débit par seconde exploitable.
  • sum(...) by (label) groupe l'agrégation par dimension ; without fait l'inverse (exclut des labels du groupement).
  • Le calcul du taux d'erreur (5xx / total * 100) et du P95 (histogram_quantile) sont les deux requêtes à maîtriser en priorité.

Exercices pratiques

1 disponible
1

Mission : le dashboard qui ment

Objectif : Corriger des requêtes PromQL mal construites qui donnent des chiffres trompeurs sur le trafic, le taux d'erreur et la latence.

Contexte

Un dashboard existant affiche http_requests_total brut sur un panel nommé "Trafic actuel", un taux d'erreur calculé avec rate() appliqué à un Gauge de connexions actives, et un P95 obtenu en appliquant histogram_quantile() directement sur les buckets bruts sans sum() by (le). Ton travail : identifier et corriger chaque requête cassée.

Résoudre l’exercice →