# Observabilité Ce document décrit ce qu'on voit du système en fonctionnement : métriques, tableaux de bord, alertes et journaux. Décision dans l'[ADR 0016](../adr/0016-supervision-en-profil-compose.md), mode d'emploi dans [`monitoring/README.md`](../../monitoring/README.md). | Brique | Sert à | Statut | |---|---|---| | Métriques de l'API | Débit, erreurs et latences par route | `Fait` | | Collecte et alertes | Prometheus, neuf règles testées, Alertmanager vers Mailpit | `Fait` | | Tableaux de bord | Grafana : API, données et modèle, infrastructure | `Fait` | | Métriques d'Airflow | StatsD ou OpenTelemetry des DAGs | `Cible` | | Journaux centralisés | Loki ou équivalent | `Cible` | ## Vue d'ensemble ```mermaid flowchart LR subgraph projet["Projet Compose de la prod"] api["backend
/metrics"] db[("db
TimescaleDB")] mail["mailpit"] garage["garage
:3903/metrics"] subgraph sup["Profil monitoring"] prom["prometheus
15 s, 15 jours"] am["alertmanager"] graf["grafana"] pge["postgres-exporter"] node["node-exporter"] cad["cadvisor"] end end hote["Hôte : VM ENI
recette et prod"] prom -->|"Bearer APP_METRICS_TOKEN"| api prom --> pge & node & cad prom -->|"Bearer GARAGE_METRICS_TOKEN"| garage pge -->|"rôle supervision"| db node -.->|"/proc, /sys"| hote cad -.->|"cgroups"| hote prom -->|"règles franchies"| am -->|"SMTP"| mail graf --> prom graf -->|"rôle supervision, SQL"| db ``` Tout vit dans le projet Compose de la prod, sur son réseau. La recette n'a pas de supervision propre. node-exporter et cAdvisor voient pourtant tout l'hôte : la mémoire de la VM et de chaque conteneur couvre donc aussi la recette, qu'on distingue au préfixe `enervision-rec-`. ## Ce que mesure chaque source | Source | Métriques utiles | Où les lire | |---|---|---| | API (`prometheus-fastapi-instrumentator`) | `http_requests_total` par route et classe de statut, `http_request_duration_seconds` par route (seaux 50 ms à 2,5 s), `http_request_duration_highr_seconds` global, mémoire du processus | Tableau « API » | | postgres-exporter | `pg_up`, connexions par état, `max_connections`, transactions validées, taille des bases | Tableau « Infrastructure » | | node-exporter | Processeur, mémoire disponible, espace disque de `/` | Tableau « Infrastructure » | | cAdvisor | Mémoire (`working_set`) et processeur par conteneur | Tableau « Infrastructure » | | TimescaleDB, en SQL | Fraîcheur des relevés par site, relevés ingérés par heure, alertes par sévérité, `drift_report` | Tableau « Données et modèle » | | Garage (`/metrics` du port admin, jeton `GARAGE_METRICS_TOKEN`) | `api_s3_request_counter`, `block_bytes_written`, `garage_local_disk_avail`, `cluster_healthy` | Prometheus seulement, aucun tableau dédié ; `CibleInjoignable` couvre son indisponibilité ([ADR 0019](../adr/0019-stockage-objet-garage-et-cycle-de-vie-des-mesures.md)) | Deux choix de l'instrumentation se lisent dans ces courbes : - **Les sondes `/health/*` et `/metrics` ne sont pas comptées.** La sonde Docker frappe toutes les 30 s : incluse, elle ferait baisser la latence moyenne et gonfler le débit d'une API au repos. - **Les seaux par route encadrent 500 ms**, seuil de charge de l'ADR 0015. Grafana lit ainsi le même p95 que k6 pendant un tir. ## Alertes | Groupe | Alertes | Sévérité | |---|---|---| | API | Indisponible 2 min, 5xx au-delà de 5 %, p95 au-delà d'une seconde | critical, critical, warning | | Base | PostgreSQL injoignable 2 min, connexions au-delà de 80 % | critical, warning | | Hôte | Mémoire au-delà de 90 %, disque sous 10 %, processeur au-delà de 90 % | warning, critical, warning | | Supervision | Un exporteur muet 5 min | warning | - **Tests des règles.** Chaque règle a un cas dans `monitoring/prometheus/tests/`, joué par `promtool test rules` dans le job Infra de la CI. Une règle qui ne se déclenche plus, ou se déclenche à tort, casse la CI avant d'atteindre la prod. - **Envoi.** Alertmanager groupe les alertes par nom et sévérité et les envoie par courriel via Mailpit, qui les capture sans rien relayer. Un `critical` est rappelé toutes les heures, un `warning` toutes les douze. Un `critical` masque le `warning` de la même cible. ## Sécurité - **Aucune interface exposée.** Prometheus, Alertmanager et Grafana n'écoutent que sur `127.0.0.1`, et rien ne passe par le proxy (ADR 0007). Accès par tunnel SSH. - **`/metrics` gardé par jeton.** Il n'est pas routé par nginx, et Prometheus y présente `APP_METRICS_TOKEN`, que l'API exige dès qu'il est posé. Le jeton lui parvient en secret Compose, jamais en clair dans sa configuration. - **Base en lecture seule.** Grafana et postgres-exporter lisent la base par le rôle `supervision`, en lecture seule, limité aux tables métier (`db/roles/supervision.sql`). Ils n'ont ni `app_user`, ni jetons, ni journal d'audit. - **Grafana verrouillé.** Il refuse de démarrer sans `GRAFANA_ADMIN_PASSWORD`. Inscription, accès anonyme et appels sortants (statistiques d'usage, vérification de mises à jour) y sont désactivés. - **cAdvisor en `privileged`.** Il tourne ainsi pour lire les cgroups, avec des montages en lecture seule et sans port publié. ## Journaux Les journaux restent ceux de Docker : `docker compose logs`, `make stack-logs`, `make monitoring-logs`. L'API écrit du JSON dès `APP_ENV=prod`, caviardé des jetons et des mots de passe (voir [20-backend.md](20-backend.md)). Aucune agrégation centralisée n'est en place. ## Ce qui manque | Manque | Conséquence assumée | |---|---| | Métriques d'Airflow (StatsD, OpenTelemetry) | Un DAG qui échoue ne se voit que dans Airflow ; le tableau « Données » le trahit indirectement par des relevés qui vieillissent | | Alerte sur la fraîcheur des relevés | Visible dans Grafana, mais aucune règle Prometheus ne la porte : il faudrait une métrique calculée par l'API ou un exportateur SQL | | Journaux centralisés | Un incident se diagnostique conteneur par conteneur | | Destinataire réel des alertes | Mailpit capture tout : les alertes se lisent dans son interface, elles ne réveillent personne |