Imagine le tableau de bord d'une voiture. Les compteurs (vitesse, régime moteur, niveau d'essence) donnent une valeur numérique à chaque instant : ce sont les métriques. La boîte noire, l'enregistreur d'événements d'une voiture moderne, note ce qui s'est passé, ligne par ligne, avec l'heure exacte : ce sont les logs (les journaux). Les voyants (huile, batterie, moteur) s'allument seuls quand une valeur surveillée sort de sa plage normale, sans que tu aies à fixer chaque compteur en permanence : ce sont les alertes. Le GPS, qui retrace le trajet complet que tu as suivi avec le temps passé sur chaque tronçon, c'est une trace. Cette image revient dans tout le module : chaque service du labo joue le rôle d'une de ces quatre pièces.
| Pièce du tableau de bord | Ce qu'elle représente | Service du labo qui joue ce rôle |
|---|---|---|
| Compteurs | Métriques | Prometheus (qui lit node-exporter, cadvisor et l'API) |
| Boîte noire | Logs | Loki, alimenté par Alloy |
| Voyants | Alertes | Alertmanager, qui prévient le webhook |
| GPS qui retrace le trajet | Traces | Aucun dans ce labo (mention au module 7) |
| Le pare-brise | Ce que tu regardes, toi | Grafana |
On n'observe pas un système par plaisir. On l'observe parce qu'un jour quelque chose casse, et qu'il faut comprendre quoi, où, et depuis quand, avant que ça coûte cher. Les trois pannes ci-dessous sont publiques : chaque entreprise a écrit et publié elle-même son propre post-mortem. Elles montrent ce que l'observabilité permet, et ce qu'elle ne permet pas toujours du premier coup.
Cloudflare, 18 novembre 2025 : quand les métriques ne suffisent pas seules. À 11h20 UTC, le réseau de Cloudflare cesse de router correctement une grande partie du trafic mondial : les visiteurs des sites de ses clients reçoivent une page d'erreur. La cause : un changement de permissions sur un cluster de base de données ClickHouse fait doubler la taille d'un fichier de configuration interne (le fichier de « caractéristiques » du système anti-bot), qui dépasse une limite fixée dans le code et fait planter le proxy central. Les métriques d'erreurs HTTP 5xx sont visibles dès la première minute, en un pic net sur un graphique. Mais le fichier n'était généré de façon défectueuse que par intermittence, sur une partie seulement du cluster : le trafic se rétablissait puis retombait en panne toutes les cinq minutes. Cette fluctuation a d'abord fait croire à l'équipe qu'il s'agissait d'une attaque par déni de service, pas d'une panne interne. Il a fallu croiser les métriques avec les journaux du module anti-bot pour identifier la vraie cause. Le trafic principal est rétabli à 14h30, tous les systèmes reviennent à la normale à 17h06 : près de 5 heures et 46 minutes entre le début et la fin complète de l'incident. Source officielle : Cloudflare outage on November 18, 2025.
AWS S3, 28 février 2017 : quand l'outil de supervision dépend du système qu'il surveille. À 9h37 (heure du Pacifique), un ingénieur d'Amazon S3 exécute une commande de maintenance censée retirer quelques serveurs d'un sous-système de facturation, dans la région Virginie du Nord (us-east-1). Une erreur de saisie retire un nombre de serveurs bien plus grand que prévu et fait tomber deux sous-systèmes critiques de S3 : l'index (les métadonnées et l'emplacement des objets) et le placement (l'allocation du nouveau stockage). S3 devient incapable de traiter les requêtes GET, LIST, PUT et DELETE, et avec lui tombent les nouveaux démarrages d'instances EC2, l'EBS, Lambda, et le tableau de bord officiel de statut d'AWS lui-même, qui dépendait de S3 pour se mettre à jour. AWS a dû communiquer l'état de la panne sur son fil Twitter. L'index est pleinement rétabli à 13h18, le placement à 13h54 : environ 4 heures et 17 minutes entre le début de l'incident et le retour à la normale. Source officielle : Summary of the Amazon S3 Service Disruption in the Northern Virginia (US-EAST-1) Region.
GitHub, 14 août 2024 : quand la supervision elle-même déclenche la panne. À 22h59 UTC, GitHub déploie un changement de configuration sur ses bases de données. Ce changement casse la capacité de ces bases à répondre correctement aux tests de santé (health checks) envoyés par la couche de routage. Ne recevant plus de réponse valide, la couche de routage déclare ces bases « en mauvaise santé » et retire l'accès en lecture : GitHub.com devient inaccessible pour tous les utilisateurs de 23h02 à 23h38 UTC, soit 36 minutes. L'équipe corrige en annulant le changement de configuration, puis confirme par une surveillance continue que la connectivité est rétablie avant de clore l'incident à 00h30 le lendemain. Le point à retenir : ce n'est pas l'absence de supervision qui a causé la panne, c'est un des mécanismes de supervision lui-même, le test de santé, qui, mal configuré, l'a déclenchée. Source officielle : GitHub Availability Report: August 2024.
Les trois pannes se recoupent sur un point : dans les trois cas, l'entreprise savait très vite que quelque chose n'allait pas (les métriques d'erreur bougent en quelques secondes). Ce qui prend du temps, c'est de savoir pourquoi. C'est exactement ce que le labo de ce cours te fait construire, en petit, sur ton poste.
Le monitoring surveille des indicateurs choisis à l'avance, avec des seuils déjà connus : « le taux d'erreurs dépasse 5 % ». C'est efficace pour une panne qu'on a déjà vue passer. L'observabilité est la capacité à comprendre l'état interne d'un système à partir des signaux qu'il produit déjà (ses métriques, ses logs, ses traces), y compris pour une question qu'on n'avait pas anticipée, sans redéployer de code pour aller la chercher. Le monitoring dit « quelque chose ne va pas » ; l'observabilité aide à répondre « pourquoi, où, et depuis quand ».
| Terme | Définition en une phrase | Où on le retrouve dans le labo |
|---|---|---|
| Monitoring | Surveiller des indicateurs connus à l'avance et alerter quand un seuil est franchi. | Les dix règles de prometheus/regles/alertes.yml (module 6) |
| Observabilité | Comprendre l'état interne d'un système à partir de ses métriques, logs et traces, même pour une question imprévue. | L'ensemble Prometheus, Loki et Grafana du labo |
| Métrique | Une valeur numérique mesurée à intervalles réguliers, qui forme une série dans le temps. | http_requetes_total, exposée par l'API sur /metrics |
| Log | Un message horodaté qu'un programme écrit à un instant précis pour décrire un événement. | Une ligne JSON écrite par l'API sur sa sortie standard, lue par journal api |
| Trace | Le trajet complet d'une requête à travers plusieurs services, avec la durée de chaque étape. | Mentionnée dans ce cours, pas outillée dans ce labo (module 7) |
| Alerte | Une notification automatique envoyée quand une condition mesurée reste vraie pendant une durée donnée. | APIInjoignable, routée par Alertmanager vers le webhook |
| SLI (Service Level Indicator) | Une mesure quantitative du niveau de service réellement observé. | Le taux de réponses 5xx de l'API sur 5 minutes (api:taux_erreurs_5m) |
| SLO (Service Level Objective) | L'objectif interne fixé sur un SLI, sur une période donnée. | « Moins de 5 % d'erreurs » : le seuil de l'alerte TauxErreursEleve |
| SLA (Service Level Agreement) | L'engagement contractuel envers un client, avec une pénalité en cas de non-respect. | Hors labo : une clause dans un contrat client |
Référence pour les définitions de SLI, SLO et SLA : Google SRE Book — Service Level Objectives. Pour l'observabilité vue par les outils du cours : Prometheus — Overview et Grafana — Observability.
La différence essentielle entre monitoring et observabilité : le monitoring répond à des questions écrites à l'avance (« le taux d'erreurs dépasse-t-il 5 % ? »). L'observabilité permet de poser une question qu'on n'avait pas prévue (« quelles requêtes ont mis plus de 500 ms entre 19h33 et 19h34 ? ») et d'obtenir la réponse à partir de ce que le système a déjà enregistré.
Avant Prometheus et Grafana, l'équipe plateforme se connectait en SSH au serveur et tapait grep ERROR /var/log/api.log. Ça fonctionne, pour une seule machine, un seul fichier, un seul moment. Mais :
grep ne voit que ce qui est écrit sur ce serveur, dans ce fichier. Avec plusieurs conteneurs de l'API qui tournent en parallèle, il faut se connecter à chacun et recouper à la main.grep ne garde pas d'historique au-delà du fichier courant : quand le fichier tourne (log rotation) ou que le conteneur redémarre, ce qui n'a pas été lu est perdu.grep ne calcule pas de tendance : il montre des lignes, pas une courbe de « pourcentage d'erreurs sur les cinq dernières minutes ».SELECT count(*) FROM inscriptions) dit combien d'inscriptions existent maintenant. Elle ne dit rien sur la latence des requêtes HTTP, sur le taux d'erreur, ni sur l'état des conteneurs : ces informations ne sont pas dans cette base.grep, ni la requête SQL, ne préviennent personne automatiquement. Il faut se souvenir de les lancer, encore et encore, ou attendre qu'un utilisateur se plaigne.L'observabilité répond à ces manques : elle centralise les métriques et les logs de toutes les instances, elle garde un historique interrogeable, elle calcule des tendances, et elle prévient automatiquement, sans attendre qu'on pose la question.
Tu rejoins l'équipe qui fait tourner la plateforme de cours en ligne utilisée dans les autres cours du catalogue. Le cœur du système est une API, l'API catalogue, écrite en Python avec FastAPI, qui expose 64 cours (C0001 à C0064) sur les routes /cours, /cours/{id}, /inscriptions, /lent, /sante et /metrics. Un second programme, le générateur de charge (le service charge), appelle cette API en continu, comme le feraient des centaines d'étudiants en train de parcourir le catalogue, s'inscrire à un cours, ou tomber sur une page qui n'existe plus.
Ta cheffe d'équipe pose une question simple, mais qu'aucun grep ni aucune requête SQL ne répond d'un bloc : « Est-ce que ça marche ? Pour qui ? Depuis quand ? Et pourquoi ça casse ? » Elle ne veut pas se connecter au serveur. Elle veut un tableau de bord qu'elle peut ouvrir elle-même, et une alerte qui la prévient avant qu'un étudiant n'écrive pour se plaindre.
C'est le fil rouge du cours. Chaque module ajoute une pièce : les métriques et PromQL (module 2), l'instrumentation de l'API elle-même (module 3), les tableaux de bord Grafana (module 4), les logs avec Loki (module 5), les alertes qui préviennent avant la plainte (module 6). Le module 7 réunit tout. Et à chaque étape, le labo te laisse casser volontairement un morceau de la plateforme (.\labo.ps1 casser api, casser erreurs, casser lenteur, casser disque) pour que tu apprennes à lire la panne dans les outils avant de la réparer.
| Service (nom du conteneur) | Rôle | Port sur ta machine |
|---|---|---|
api (labo-api) | Le service observé : /cours, /inscriptions, /sante, et ses propres métriques sur /metrics | 8000 |
charge (labo-charge) | Simule des étudiants qui utilisent la plateforme, pour qu'il y ait quelque chose à observer | aucun |
prometheus (labo-prometheus) | Va chercher (scrape) les métriques de chaque service toutes les 15 s, les stocke comme des séries dans le temps, évalue les règles d'alerte | 9090 |
alertmanager (labo-alertmanager) | Reçoit les alertes déclenchées par Prometheus, les regroupe, les route vers un récepteur | 9093 |
webhook (labo-webhook) | Reçoit les alertes d'Alertmanager et les affiche : ce qu'un système d'astreinte recevrait | 8090 |
alloy (labo-alloy) | Découvre les conteneurs Docker et transporte leurs logs vers Loki | 12345 |
loki (labo-loki) | Stocke les logs et les indexe par étiquettes (labels), pas par leur texte complet | 3100 |
node-exporter (labo-node-exporter) | Expose les métriques de la machine hôte (CPU, mémoire, disque) au format Prometheus | 9100 |
cadvisor (labo-cadvisor) | Expose les métriques de chaque conteneur (CPU, mémoire, réseau) au format Prometheus | 8080 |
grafana (labo-grafana) | Interface unique pour explorer et visualiser Prometheus, Loki et Alertmanager | 3000 (GRAFANA_PORT) |
Tu n'as pas encore installé le labo : c'est le travail des leçons 03 et 04. Ce pas à pas te fait lire quatre sorties réelles, capturées sur la machine du cours, pour que tu reconnaisses une métrique, un log et une alerte quand tu les produiras toi-même. Garde cette page ouverte pendant la leçon 04 : tu retrouveras chacune de ces quatre sorties à l'écran.
Une métrique, telle que Prometheus la lit. Toutes les 15 secondes, Prometheus appelle http://api:8000/metrics. Voici quatre lignes de cette page, sur la machine du cours :
# HELP http_requetes_total Nombre de requêtes HTTP reçues, par méthode, route normalisée et code de réponse.
# TYPE http_requetes_total counter
http_requetes_total{code="200",methode="GET",route="/cours"} 3247.0
http_requetes_total{code="500",methode="GET",route="/cours"} 32.0Ce qu'il faut voir : une métrique a un nom (http_requetes_total), des labels entre accolades (code, methode, route) et une valeur (3247.0). Les deux lignes ont le même nom mais des labels différents : ce sont deux séries distinctes. La ligne # TYPE … counter dit que ce nombre ne fait qu'augmenter. La leçon 02 détaille les quatre types.
Un log, tel que l'API l'écrit. L'API écrit une ligne JSON par requête sur sa sortie standard. .\labo.ps1 journal api les affiche ; en voici deux, sur la machine du cours :
labo-api | {"horodatage": "2026-09-15T19:33:25.839+00:00", "niveau": "INFO", "id_requete": "46bb533b33e9", "methode": "GET", "route": "/cours/{id}", "code": 200, "duree_ms": 13.9, "message": "GET /cours/C0038 -> 200"}
labo-api | {"horodatage": "2026-09-15T19:33:14.781+00:00", "niveau": "ERROR", "id_requete": "dc1c2ff189a6", "methode": "GET", "route": "/cours/{id}", "code": 500, "duree_ms": 0.1, "message": "GET /cours/C0019 -> 500"}Ce qu'il faut voir : un log est un événement précis (cette requête-là, à cet instant-là, pour le cours C0038), là où la métrique de l'étape 1 est un cumul (3247 requêtes /cours réussies depuis le démarrage). Le champ id_requete identifie une requête unique ; la même valeur est renvoyée au client dans l'en-tête HTTP x-id-requete. La seconde ligne est une erreur 500 : le labo en produit volontairement 1 % en fonctionnement normal.
Une alerte, telle que l'équipe d'astreinte la reçoit. Quand l'API est arrêtée (casser api), Prometheus ne peut plus lire /metrics, la règle APIInjoignable passe à firing après 30 secondes, Alertmanager la transmet au webhook. Voici ce que http://localhost:8090/alertes.json contient alors, sur la machine du cours :
{"recu_a":"2026-09-15T19:41:26+00:00","etat":"firing","nom":"APIInjoignable","severite":"critique","service":"api","resume":"L'API catalogue ne répond plus","description":"Prometheus n'arrive plus à lire http://api:8000/metrics depuis 30 secondes (cible api:8000).","debut":"2026-09-15T19:41:11.496Z","fin":"0001-01-01T00:00:00Z"}Ce qu'il faut voir : l'alerte a un nom, une sévérité, un résumé lisible par un humain, et un état firing (elle sonne). Le champ fin vaut une date nulle tant que l'alerte est en cours ; après reparer, une seconde notification arrive avec "etat":"resolved" et une vraie date de fin. Personne n'a eu à rafraîchir une page : le voyant s'est allumé seul.
La vue d'ensemble, en une commande. .\labo.ps1 etat résume l'état des dix services et de la supervision. Sur la machine du cours, en fonctionnement normal :
== Supervision ==
✔ Prometheus répond — cibles up : 8/8
séries en mémoire : 12350
alertes : 0 active(s), 0 en attente (pending)
✔ Alertmanager répond (http://localhost:9093)
✔ Grafana répond (http://localhost:3000)
✔ Loki répond (http://localhost:3100)
✔ API catalogue répond — version 1.0.0, 64 cours
✔ Webhook répond — 0 alerte(s) reçue(s) (http://localhost:8090)
Labo : 10/10 services, 8/8 cibles up, 0 alertes actives.Ce qu'il faut voir : 8/8 cibles up (Prometheus lit huit pages /metrics : les dix services moins charge et webhook, qui n'en exposent pas), 12350 séries en mémoire (ce nombre varie d'une machine à l'autre), 0 alertes actives. C'est la ligne que tu dois retrouver à la fin de chaque pratique du cours.
La règle qui relie la métrique à l'alerte. L'alerte de l'étape 3 n'est pas sortie de nulle part : elle est écrite dans un fichier du kit, prometheus/regles/alertes.yml, dont Prometheus évalue chaque règle toutes les 15 secondes (evaluation_interval: 15s dans prometheus/prometheus.yml). Voici la première des dix règles, telle qu'elle est dans le kit :
groups:
- name: api-catalogue
rules:
- alert: APIInjoignable
expr: up{job="api"} == 0
for: 30s
labels:
severite: critique
service: api
annotations:
resume: "L'API catalogue ne répond plus"
description: "Prometheus n'arrive plus à lire http://api:8000/metrics depuis 30 secondes (cible {{ $labels.instance }})."Ce qu'il faut voir : expr est une métrique (up, celle que Prometheus fabrique lui-même à chaque lecture : 1 si la cible a répondu, 0 sinon) comparée à une valeur ; for: 30s est la durée pendant laquelle la condition doit rester vraie avant que l'alerte sonne ; resume et description sont exactement le texte que le webhook a affiché à l'étape 3, avec {{ $labels.instance }} remplacé par api:8000. Une alerte, c'est une métrique, un seuil et une durée : rien de plus. Le module 6 te fera écrire les tiennes.
Cette leçon ne te fait rien installer, mais trois confusions reviennent dès la leçon 04. Les messages ci-dessous ont été provoqués pour de vrai sur la machine du cours.
« L'API est en panne, elle répond 404 » : non. Un 404 est une réponse saine d'un service qui tourne et qui dit « cette ressource n'existe pas ». Sur le labo, http://localhost:8000/cours/C9999 répond :
HTTP 404 {"detail":"cours C9999 introuvable"}Une API réellement arrêtée ne répond rien du tout. Pendant casser api, curl http://localhost:8000/sante renvoie :
curl: (7) Failed to connect to localhost:8000 after 2237 ms: Could not connect to serverEt Invoke-RestMethod http://localhost:8000/sante sous PowerShell : Le délai de l'opération a expiré. Un 404 est un log de niveau WARNING et une métrique code="404" ; une API arrêtée, c'est up{job="api"} qui vaut 0.
« Il n'y a aucune alerte, la supervision ne marche pas » : dans Prometheus, la métrique ALERTS renvoie un résultat vide quand tout va bien. Sur la machine du cours, en fonctionnement normal, l'API de requête répond :
{"status":"success","data":{"resultType":"vector","result":[]}}"status":"success" avec "result":[] : la requête est correcte, il n'y a simplement rien à montrer. C'est la situation normale, pas une panne. ALERTS ne contient une série que pour une alerte pending ou firing.
« Une métrique et un log, c'est la même information » : non. La métrique http_requetes_total{code="500",methode="GET",route="/cours/{id}"} 27.0 dit qu'il y a eu 27 erreurs sur cette route depuis le démarrage, sans dire lesquelles. Le log "GET /cours/C0019 -> 500" avec "id_requete": "dc1c2ff189a6" dit précisément laquelle. La métrique est bon marché et se compte ; le log est détaillé et se lit. Le module 5 les relie par le champ id_requete.
Le monitoring surveille des seuils connus à l'avance ; l'observabilité permet de comprendre une panne qu'on n'avait pas anticipée, à partir des métriques, des logs et des traces qu'un système produit déjà. Une métrique est un nombre mesuré dans le temps, avec un nom, des labels et une valeur (http_requetes_total{code="200",methode="GET",route="/cours"} 3247.0). Un log est un événement horodaté, une ligne JSON par requête dans le labo, avec un id_requete unique. Une alerte prévient automatiquement quand une condition reste vraie assez longtemps (APIInjoignable après 30 secondes d'API injoignable) et arrive au webhook avec un état firing puis resolved. Le tableau de bord d'une voiture résume tout : compteurs = métriques, boîte noire = logs, voyants = alertes, GPS = traces, pare-brise = Grafana. Ni un grep sur un seul serveur ni une requête SQL sur la base métier ne centralisent l'historique, ne calculent une tendance, ni ne préviennent automatiquement. Un 404 est la réponse saine d'un service qui tourne ; une API arrêtée ne répond rien et up vaut 0. Le fil rouge du cours est la plateforme de cours en ligne, son API catalogue de 64 cours, son générateur de charge et ses dix services.
casser et reparer./metrics du labo : les quatre types de métriques, les labels, la cardinalité, le pull, et la structure exacte d'une ligne de log JSON.