Le duo Prometheus + Grafana

Prometheus collecte et stocke les métriques. Grafana les affiche sous forme de dashboards interactifs. C'est le tandem standard du monitoring open source : on branche Grafana sur Prometheus en tant que source de données, et on construit ses graphiques côté Grafana. Si tu débutes, lis cette fiche puis enchaîne sur la fiche Grafana.

À quoi ça sert

Quand ton API FastAPI tourne en production, tu veux savoir : combien de requêtes par seconde elle reçoit, combien échouent, combien de temps elle met à répondre, combien de prédictions ton modèle fait par minute… Ces chiffres sont des métriques, et elles changent dans le temps.

Prometheus s'occupe de trois choses :

  • Scraping — il va chercher tout seul, toutes les 15 secondes par défaut, les métriques exposées par tes services sur une URL /metrics.
  • Stockage time-series — il garde l'historique de chaque métrique avec son timestamp, dans une base optimisée pour ça.
  • Requêtes (PromQL) — un langage pour calculer taux, moyennes, percentiles, et déclencher des alertes (« si le taux d'erreur dépasse 5 % pendant 2 minutes, préviens-moi »).
En une phrase

Prometheus = un robot qui passe toutes les 15 secondes demander leurs chiffres à tes services, les range dans une base, et te laisse poser des questions dessus.

Pull vs push

Prometheus fonctionne en pull : c'est lui qui va chercher les métriques, pas tes services qui les envoient. Conséquence pratique : tes services n'ont qu'à exposer /metrics en HTTP, sans rien savoir de Prometheus. Pour les jobs courts (cron, batch) qui n'existent pas assez longtemps pour être scrapés, il existe un Pushgateway intermédiaire.

Un exemple d'usage

Tu as déployé une API FastAPI qui sert un modèle de prédiction. Tu veux mesurer le nombre de prédictions par seconde et le temps de réponse. Avec la lib prometheus-client, ça tient en quelques lignes :

python
from fastapi import FastAPI
from prometheus_client import Counter, Histogram, make_asgi_app

app = FastAPI()

predictions = Counter("predictions_total", "Nombre total de prédictions")
latency = Histogram("prediction_latency_seconds", "Temps de prédiction")

# Expose /metrics au format Prometheus
app.mount("/metrics", make_asgi_app())

@app.post("/predict")
def predict(payload: dict):
    with latency.time():
        result = {"label": "chat"}  # ton vrai modèle ici
    predictions.inc()
    return result

Une fois l'API lancée, curl http://localhost:8000/metrics renvoie un texte brut comme :

text
predictions_total 42.0
prediction_latency_seconds_bucket{le="0.1"} 38.0
prediction_latency_seconds_bucket{le="0.5"} 41.0
prediction_latency_seconds_count 42.0
prediction_latency_seconds_sum 2.137

C'est ce format que Prometheus va aspirer toutes les 15 secondes pour en faire un historique exploitable.

How-to : installer et utiliser Prometheus

  1. Lancer Prometheus avec Docker

    Le plus simple est d'utiliser l'image officielle. Crée d'abord un fichier de config prometheus.yml à la racine de ton projet :

    yaml
    # prometheus.yml — configuration minimale
    global:
      scrape_interval: 15s
    
    scrape_configs:
      - job_name: "mon-api"
        static_configs:
          - targets: ["host.docker.internal:8000"]

    host.docker.internal permet au conteneur Prometheus de joindre un service qui tourne sur ta machine hôte (sous Linux, ajoute --add-host=host.docker.internal:host-gateway).

    bash
    docker run -d --name prometheus \
      -p 9090:9090 \
      -v "$(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml" \
      prom/prometheus

    Ouvre http://localhost:9090 : c'est l'UI web (basique mais utile pour tester des requêtes).

  2. Instrumenter une app Python

    Installe la lib cliente :

    bash
    uv add prometheus-client

    Quatre types de métriques à connaître :

    • Counter — un compteur qui ne fait que monter (requêtes reçues, erreurs, prédictions). Jamais décrémenté.
    • Gauge — une valeur instantanée qui peut monter ou descendre (mémoire utilisée, nombre de connexions actives).
    • Histogram — distribue les valeurs dans des « buckets » (idéal pour les latences : combien sous 100ms, sous 500ms…).
    • Summary — calcule directement les percentiles côté app. Plus rare, préfère Histogram en général.
  3. Vérifier que ça scrape

    Dans l'UI Prometheus (:9090), va dans Status → Targets. Tu dois y voir ton job mon-api en UP. Si c'est DOWN, vérifie l'URL et que /metrics répond bien quand tu fais un curl dessus.

    Erreur classique

    Si Prometheus tourne dans Docker et ton API en local, localhost dans prometheus.yml ne marchera pas (il pointe sur le conteneur lui-même, pas sur ta machine). Utilise host.docker.internal.

  4. Premières requêtes PromQL

    Toujours dans l'UI Prometheus, onglet Graph. Quelques requêtes utiles :

    promql
    # Valeur courante du compteur
    predictions_total
    
    # Taux de prédictions par seconde, moyenné sur 1 min
    rate(predictions_total[1m])
    
    # Latence p95 sur 5 min
    histogram_quantile(0.95, rate(prediction_latency_seconds_bucket[5m]))
    
    # Taux d'erreur HTTP 5xx (si tu as un Counter avec un label "status")
    rate(http_requests_total{status=~"5.."}[5m])

    rate() est l'opérateur le plus important : il transforme un compteur cumulé en « événements par seconde ».

  5. Ajouter des labels

    Une métrique seule, c'est limité. Avec des labels, tu peux découper la même métrique selon plusieurs dimensions :

    python
    predictions = Counter(
        "predictions_total",
        "Nombre de prédictions",
        ["model_version", "label"],  # dimensions
    )
    
    predictions.labels(model_version="v2", label="chat").inc()

    Tu peux ensuite filtrer en PromQL : rate(predictions_total{model_version="v2"}[1m]).

    Attention à l'explosion de cardinalité

    N'utilise jamais un user_id ou un timestamp comme label : chaque combinaison crée une nouvelle série. Quelques centaines de valeurs maxi par label, sinon Prometheus s'écroule.

  6. Brancher Grafana par-dessus

    L'UI Prometheus dépanne pour tester une requête, mais pour les vrais dashboards on passe à Grafana. Le plus rapide : ajouter un service Grafana à ton docker-compose.yml, et configurer Prometheus comme source de données (URL : http://prometheus:9090 si les deux conteneurs sont sur le même réseau Docker). La suite est détaillée dans la fiche Grafana.

  7. Ajouter des exporters

    Pour monitorer des choses que tu n'écris pas toi-même (machine, base de données, conteneurs Docker), Prometheus utilise des exporters : des petits programmes qui exposent /metrics à la place du système qu'ils mesurent. Les plus utiles :

    • node_exporter — CPU, RAM, disque, réseau de la machine.
    • cadvisor — métriques par conteneur Docker.
    • postgres_exporter — métriques d'une base PostgreSQL.

    Tu les ajoutes simplement comme un nouveau job dans prometheus.yml.

Aide-mémoire

python (prometheus-client)
from prometheus_client import Counter, Gauge, Histogram

c = Counter("events_total", "desc", ["kind"])
c.labels(kind="ok").inc()

g = Gauge("queue_size", "desc")
g.set(12)
g.inc()  # ou .dec()

h = Histogram("duration_seconds", "desc")
with h.time():
    do_work()
promql (requêtes courantes)
# Taux par seconde sur 5 min
rate(metric_total[5m])

# Somme par label
sum by (status) (rate(http_requests_total[5m]))

# Pourcentage d'erreurs
sum(rate(http_requests_total{status=~"5.."}[5m]))
  / sum(rate(http_requests_total[5m]))

# Percentile depuis un Histogram
histogram_quantile(0.99, rate(latency_bucket[5m]))
bash (Docker)
docker run -d -p 9090:9090 \
  -v "$(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml" \
  prom/prometheus

# Recharger la config sans restart (si --web.enable-lifecycle)
curl -X POST http://localhost:9090/-/reload

Prometheus et le reste de l'écosystème

  • Grafana — l'UI Prometheus est rudimentaire. En vrai, on connecte Grafana à Prometheus comme source de données et on construit les dashboards là-bas. Voir l'encart en haut de page : c'est le duo standard.
  • FastAPI — instrumentation en 3 lignes avec prometheus-client ou la lib prometheus-fastapi-instrumentator qui ajoute automatiquement latence et codes HTTP.
  • Docker — Prometheus tourne typiquement en conteneur, à côté de tes services, dans un même docker-compose.yml.
  • Kubernetes — l'opérateur kube-prometheus-stack (un Helm chart) déploie en une commande Prometheus + Grafana + alertmanager + exporters K8s. C'est l'installation standard en prod.
  • MLflow — MLflow suit tes entraînements (offline), Prometheus suit ton modèle en production (online). Les deux sont complémentaires : MLflow pour choisir le modèle, Prometheus pour vérifier qu'il se comporte bien une fois déployé.
  • CI/CD — un pipeline peut lancer un test de charge et vérifier que la latence p95 mesurée par Prometheus reste sous un seuil avant de promouvoir une nouvelle version.
Quoi monitorer en MLOps

Pour un service qui sert un modèle, vise au minimum : nombre de prédictions par seconde, latence p50/p95/p99, taux d'erreur, distribution des classes prédites (pour détecter une dérive : si ton modèle prédit soudain 90 % de « chat », il y a peut-être un problème en amont).

Pour aller plus loin