Aller au contenu
Outils medium

PromQL : Le langage de requête Prometheus

12 min de lecture

PromQL (Prometheus Query Language) est le langage de requête de Prometheus. Ce guide vous accompagne des bases aux requêtes avancées, avec des exemples concrets que vous pouvez tester immédiatement.

Accédez à l’interface Prometheus (http://localhost:9090) et utilisez l’onglet Graph pour tester vos requêtes.

Interface PromQL de Prometheus

Tapez le nom d’une métrique pour voir toutes ses séries :

up

Résultat : toutes les séries de la métrique up, une par target scrapée.

up{instance="localhost:9090", job="prometheus"} 1
up{instance="node1:9100", job="node"} 1
up{instance="node2:9100", job="node"} 0

Les sélecteurs de labels filtrent les séries :

up{job="node"}

Opérateurs de matching :

OpérateurDescriptionExemple
=Égalité exactejob="prometheus"
!=Différent dejob!="test"
=~Regex matchjob=~"node.*"
!~Regex not matchjob!~"test.*"

Exemples pratiques :

# Toutes les requêtes HTTP sauf les 200
http_requests_total{status!="200"}
# Méthodes GET ou POST
http_requests_total{method=~"GET|POST"}
# Namespaces commençant par "prod"
container_memory_usage_bytes{namespace=~"prod.*"}

PromQL manipule quatre types de données :

TypeDescriptionExemple
Instant vectorValeurs actuelles (un point par série)up
Range vectorValeurs sur une périodeup[5m]
ScalarNombre flottant3.14
StringChaîne (rarement utilisé)"hello"

C’est le type le plus courant. Chaque série a une seule valeur (la dernière).

node_memory_MemAvailable_bytes

Sélectionne toutes les valeurs sur une période. Nécessaire pour les fonctions comme rate().

http_requests_total[5m]

Périodes disponibles : s (secondes), m (minutes), h (heures), d (jours), w (semaines), y (années).

Les opérateurs classiques fonctionnent sur les séries :

# Mémoire utilisée en pourcentage
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)
/ node_memory_MemTotal_bytes * 100
# Conversion bytes → gigabytes
node_filesystem_size_bytes / 1024 / 1024 / 1024
OpérateurDescription
+Addition
-Soustraction
*Multiplication
/Division
%Modulo
^Puissance

Retournent 1 (vrai) ou filtrent les séries :

# Instances avec CPU > 80%
instance:cpu_usage:percent > 80
# Garder uniquement les séries au-dessus du seuil
http_request_duration_seconds > 0.5
OpérateurDescription
==Égal
!=Différent
>Supérieur
<Inférieur
>=Supérieur ou égal
<=Inférieur ou égal

Pour combiner des vecteurs :

# Séries présentes dans les deux (intersection)
metric_a and metric_b
# Séries présentes dans l'un ou l'autre (union)
metric_a or metric_b
# Séries de A absentes de B
metric_a unless metric_b

La fonction la plus importante. Calcule le taux par seconde d’un counter.

# Requêtes par seconde (sur 5 minutes)
rate(http_requests_total[5m])

Comme rate() mais utilise uniquement les 2 derniers points. Plus réactif mais plus bruité.

# Taux instantané (derniers 5 min de données)
irate(http_requests_total[5m])

Nombre total d’augmentations sur la période.

# Nombre de requêtes sur 1 heure
increase(http_requests_total[1h])

Agrègent plusieurs séries en une.

# Total des requêtes (toutes instances)
sum(rate(http_requests_total[5m]))
# Moyenne de mémoire par node
avg(node_memory_MemAvailable_bytes)
# Maximum de CPU
max(instance:cpu_usage:percent)

Utilisez by ou without pour contrôler l’agrégation :

# Somme par job
sum by(job) (rate(http_requests_total[5m]))
# Somme en ignorant le label instance
sum without(instance) (rate(http_requests_total[5m]))

Calcule les percentiles depuis un histogram.

# P95 de latence par job
histogram_quantile(0.95,
sum by(job, le) (rate(http_request_duration_seconds_bucket[5m]))
)
# P99 global
histogram_quantile(0.99,
sum by(le) (rate(http_request_duration_seconds_bucket[5m]))
)
FonctionDescriptionExemple
abs()Valeur absolueabs(delta(temp[1h]))
ceil()Arrondi supérieurceil(value)
floor()Arrondi inférieurfloor(value)
round()Arrondiround(value, 0.1)
ln()Logarithme naturelln(value)
log2()Log base 2log2(value)
log10()Log base 10log10(value)
sqrt()Racine carréesqrt(value)
FonctionDescription
time()Timestamp Unix actuel
timestamp()Timestamp de chaque sample
day_of_week()Jour de la semaine (0-6)
hour()Heure (0-23)
# Alerte uniquement en heures ouvrées
up == 0 and hour() >= 9 and hour() <= 18
FonctionDescription
avg_over_time()Moyenne sur la période
min_over_time()Minimum sur la période
max_over_time()Maximum sur la période
sum_over_time()Somme sur la période
count_over_time()Nombre de points
stddev_over_time()Écart-type
changes()Nombre de changements
resets()Nombre de resets (counter)
delta()Différence premier-dernier
deriv()Dérivée (pente)
predict_linear()Prédiction linéaire
# Moyenne de CPU sur 1 heure
avg_over_time(instance:cpu_usage:percent[1h])
# Prédiction : dans 4h, espace disque
predict_linear(node_filesystem_avail_bytes[6h], 4*3600)
# Pourcentage CPU utilisé par instance
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

Explication :

  1. node_cpu_seconds_total{mode="idle"} : temps CPU en idle
  2. rate(...[5m]) : taux par seconde sur 5 min
  3. avg by(instance) : moyenne des cores par machine
  4. * 100 : conversion en pourcentage
  5. 100 - ... : usage = 100% - idle
# Pourcentage mémoire utilisée
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
# Taux d'erreurs 5xx sur le total
sum(rate(http_requests_total{status=~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) * 100
# P95 par endpoint
histogram_quantile(0.95,
sum by(handler, le) (rate(http_request_duration_seconds_bucket[5m]))
)
# Prédiction : disque plein dans combien de temps (secondes)
(node_filesystem_avail_bytes / node_filesystem_size_bytes)
/ deriv(node_filesystem_avail_bytes[6h]) * -1
# Top 5 pods par mémoire
topk(5, container_memory_usage_bytes{container!=""})

Comparer avec le passé :

# Différence avec il y a 1 semaine
rate(http_requests_total[5m])
- rate(http_requests_total[5m] offset 1w)

Quand vous combinez deux vecteurs, PromQL fait du matching par labels.

Chaque série d’un côté matche exactement une série de l’autre.

# Même labels des deux côtés
metric_a / metric_b

Spécifie quels labels utiliser pour le matching :

# Matcher uniquement sur le label "job"
metric_a / on(job) metric_b
# Matcher en ignorant le label "instance"
metric_a / ignoring(instance) metric_b

Pour le one-to-many ou many-to-one :

# Chaque série de B matchée à une série de A
metric_a / on(job) group_left metric_b

Suivez la convention Prometheus :

<namespace>_<name>_<unit>_<suffix>

Exemples :

  • http_requests_total (counter)
  • http_request_duration_seconds (histogram)
  • node_memory_MemAvailable_bytes (gauge)

Mauvais : rate() sur un gauge

rate(node_memory_MemAvailable_bytes[5m]) # FAUX

Correct : deriv() pour un gauge

deriv(node_memory_MemAvailable_bytes[5m])
  • Utilisez les recording rules pour les requêtes complexes fréquentes
  • Limitez la période : [5m] est souvent suffisant
  • Agrégez tôt : sum by(job) (rate(...)) plutôt que calculs sur toutes les séries
  • Évitez .* dans les regex : préférez des valeurs exactes
# === COUNTERS ===
rate(counter[5m]) # Taux par seconde
increase(counter[1h]) # Augmentation totale
irate(counter[5m]) # Taux instantané
# === AGRÉGATIONS ===
sum(metric) # Total
avg(metric) # Moyenne
max(metric) # Maximum
min(metric) # Minimum
count(metric) # Nombre de séries
sum by(label) (metric) # Grouper par label
# === PERCENTILES ===
histogram_quantile(0.95, sum by(le) (rate(histogram_bucket[5m])))
# === TEMPS ===
avg_over_time(metric[1h]) # Moyenne sur 1h
max_over_time(metric[24h]) # Max sur 24h
predict_linear(metric[6h], 3600) # Prédiction dans 1h
# === COMPARAISON ===
metric > 80 # Filtre
metric > bool 80 # Retourne 0/1
topk(5, metric) # Top 5
bottomk(3, metric) # Bottom 3
# === LABELS ===
label_replace(metric, "new", "$1", "old", "(.*)")
label_join(metric, "new", ",", "label1", "label2")
  • rate() pour les counters, deriv() pour les gauges
  • by() et without() contrôlent l’agrégation
  • histogram_quantile() pour les percentiles
  • Protégez les divisions contre le zéro
  • Testez dans l’UI avant de mettre en alerte

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.