Observabilité 2.0 : arrête de dasher, commence à comprendre
OpenTelemetry, SLOs, error budgets — comment sortir du noise pour trouver le signal.

3h du matin. L’alerte tire. “API checkout latency > 2s”. Tu ouvres Grafana. 47 dashboards. Tu cliques sur celui qui a l’air concerné. Le graph montre un spike. OK, et maintenant ? Tu sais que c’est lent. Tu sais pas pourquoi. Tu ouvres les logs. 10 000 lignes. Tu cherches le request ID… que personne n’a loggé. Tu ouvres un terminal, tu commences à grep. Tu trouves rien. Tu restart le service. Ça marche. Tu te rendors.
Et le lendemain, tu refais la même chose.
C’est ça, l’observabilité 1.0. Tu as des dashboards, mais tu comprends rien. Tu as des alertes, mais tu sais pas quoi faire. Tu as des logs, mais ils sont inutiles sans corrélation.
Observabilité 2.0, c’est pas plus d’outils. C’est mieux d’outils. C’est la différence entre un dico de 10 000 pages et Google.
Lexique
C’est là mes définitions et si elles vous déplaisent, cassez-vous je suis pas là pour discuter lexique.
- OpenTelemetry (OTLP): framework open-source CNCF qui standardise la collecte de traces, metrics, et logs. Vendor-neutral. Tu instrumentes une fois, tu exportes n’importe où.
- SLI (Service Level Indicator): mesure technique de santé d’un service. “% de requêtes < 500ms sans erreur 5xx”. La brique de base.
- SLO (Service Level Objective): cible de fiabilité. “99.9% de disponibilité sur 30 jours”. Le contrat.
- Error Budget: capacité restante avant breach du SLO. 99.9% sur 30j = 43.8 minutes de downtime autorisé. L’outil de décision.
- Tail-Based Sampling: décision de sampling après que la trace soit complète. Garde toujours les erreurs et les traces lentes.
- Exemplar: trace ID attaché à un échantillon de métrique. Le pont entre Prometheus et Tempo.
- RED Method: Rate, Errors, Duration — les trois dimensions pour mesurer un service.
- Burn Rate: vitesse à laquelle tu consommes ton error budget. Burn rate = 14.4 = budget épuisé en 2 jours.
- Prometheus: scraper de métriques. Le standard de facto.
- Loki: aggrégation de logs par labels. 1/10ème du coût d’Elasticsearch.
- Tempo: stockage de traces dans object storage. Pas d’index lourd.
- Grafana: frontend universel qui corréle métriques, logs, et traces.
Le problème avec l’observabilité 1.0
La plupart des équipes n’ont pas un problème d’observabilité. Elles ont un problème de signal-to-noise.
Tu sais ce que c’est un dashboard de 47 panneaux ? C’est un écran que tu regardes jamais. Parce que tu sais pas lequel regarder quand ça merde. Et quand tu le sais, tu sais pas corréler les métriques avec les logs, et tu sais pas jumper sur une trace.
L’observabilité 1.0, c’est trois silos :
- Prometheus pour les métriques (et tu connais les noms des métriques par cœur tellement t’en as)
- ELK pour les logs (et tu paies une fortune pour un cluster Elasticsearch qui rame)
- Rien pour les traces (ou alors Jaeger, que personne configure correctement)
Le résultat : debugging = grep dans les logs + deviner le request ID + restart de service parce que t’as pas mieux.
La stack Grafana LGTM : ce qu’il te faut
La stack officielle en 2026, c’est Loki, Grafana, Tempo, et Prometheus (+ Mimir/Thanos pour le long terme).
| Composant | Rôle | Stockage |
|---|---|---|
| Prometheus | Métriques (scrape, alerting) | TSDB local + Thanos/Mimir long terme |
| Loki | Logs (aggrégation par labels) | S3/GCS |
| Tempo | Traces (object storage) | S3/GCS |
| Grafana | Visualisation, corrélation | Métadonnées |
Pourquoi cette stack ? Parce que c’est open-source, que ça coûte 1/4 à 1/10 du coût équivalent Datadog à l’échelle, et que tout est câblé ensemble dans Grafana.
Et le composant clé qui manquait ? OpenTelemetry.
OpenTelemetry : le vrai game-changer
Pourquoi OpenTelemetry change tout
Avant OpenTelemetry, tu avais :
- Un agent Datadog pour les métriques
- Fluent Bit pour les logs
- Un tracer spécifique au vendor pour l’APM
Tu instrumentalisais trois fois, tu payais trois fois, tu maintainais trois fois.
OpenTelemetry unifie tout en un seul framework. Instrumentalise une fois, exporte n’importe où.
Les trois signaux :
- Metrics — Latence, requêtes, erreurs (RED)
- Logs — Événements structurés avec trace ID
- Traces — Chemin complet d’une requête
Ce qui rend OpenTelemetry différent
Les trois signaux partagent le même context propagation. Un trace ID qui commence dans le frontend se propage through chaque microservice. Les logs portent ce même trace ID.
Tu peux jumper d’une ligne de log à sa trace en secondes. Pas en minutes. En secondes.
Si t’as jamais fait du debugging dans un système distribué, tu sais pas ce que ça vaut. Si t’as fait, tu pleures de joie.
Auto-instrumentation vs Manual
| Aspect | Auto | Manual |
|---|---|---|
| Setup | Zero code change | Nécessite du code |
| Couverture | Frameworks (Spring, Flask) | Business logic |
| Valeur SLO | Basique (RED) | Métier (checkout time) |
| Temps | Un après-midi | Plusieurs jours |
La règle : L’auto-instrumentation fournit les 80% fondamentaux. Le manual remplit ce qui compte pour les SLOs.
En pratique : tu déploies l’auto-instrumentation un vendredi après-midi, et le lundi tu as déjà des traces. Le manual, tu le fais petit à petit pour les business metrics critiques.
L’architecture du Collector
Le OTLP Collector est le composant le plus critique. Il reçoit, traite, et exporte la télémétrie.
Architecture deux tiers
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Agent │────▶│ Gateway │────▶│ Prometheus/Tempo │
│ (DaemonSet) │ │ (Deployment) │ │ /Loki │
└─────────────────┘ └──────────────────┘ └──────────────────┘
| Tier | Rôle | Déploiement |
|---|---|---|
| Agent | Collecte locale, batching léger | DaemonSet (1 par node) |
| Gateway | Tail sampling, routing, fan-out | Deployment (2+ instances) |
Pourquoi deux tiers ? Les agents gèrent ce qui n’a de sens que par host. Les gateways gèrent ce qui n’a de sens que centralement — tail sampling, routing cross-service.
Tail-Based Sampling
Le head-based sampling (aléatoire 10%) rate la plupart des erreurs. Le tail-based sampling décide après la trace complète.
1tail_sampling:
2 decision_wait: 10s
3 policies:
4 - name: errors
5 type: status_code
6 status_code: { status_codes: [ERROR] }
7 - name: slow-traces
8 type: latency
9 latency: { threshold_ms: 1000 }
10 - name: baseline
11 type: probabilistic
12 probabilistic: { sampling_percentage: 5 }Résultat : ~11-12% du volume stocké, mais couverture quasi-complète des incidents. Tu gardes toutes les erreurs, toutes les traces lentes, et un échantillon de normal pour le contexte.
Contrainte : Le tail sampling tourne sur le gateway, pas sur les agents. C’est la contrainte topologique que les gens oublient. Si tu le mets sur un agent, il voit qu’une partie de la trace et sa peut pas décider.
Sizing
- < 20 services, < 500 RPS → un seul collector suffit
- 20-80 services, 500-5000 RPS → architecture deux tiers
- > 80 services, > 5000 RPS → architecture complète avec load balancing trace-aware
SLOs : le contrat avec la réalité
Pourquoi les SLOs comptent
Un SLO, c’est pas un indicateur technique. C’est un outil de négociation entre product et SRE.
Un SRE qui voit que 60% du budget mensuel a été consommé en 72 heures a une information actionnable. Il sait que le rythme de consommation est insoutenable, et il a un trigger clair pour changer de comportement avant le breach.
Définir des bons SLIs
La méthode RED : Rate, Errors, Duration.
| Dimension | SLI | PromQL |
|---|---|---|
| Rate | Requêtes/sec | rate(http_requests_total[5m]) |
| Errors | % erreurs | rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) |
| Duration | Latence P99 | histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) |
Important : Error rate et latency nécessitent des SLOs séparés avec des error budgets séparés. Un service peut être rapide mais cassé, ou lent mais fiable. Combiner les deux dans un seul objectif rend le budget ininterprétable.
Exemple de tableau SLOs
| Service | SLI | Target | Error Budget | Status |
|---|---|---|---|---|
| Checkout API | % requêtes < 500ms, non-5xx | 99.5% | 3h 36m restantes | HEALTHY |
| Auth Service | % validations token réussies | 99.9% | 0h 22m restantes | AT RISK |
| Search API | % requêtes résultats < 1s | 98.0% | Budget épuisé | BREACHED |
| Order Worker | % jobs sans retry | 99.0% | 5h 12m restantes | HEALTHY |
Tu vois le Search API ? Budget épuisé. Ça veut dire : freeze features, priorise fiabilité. Pas parce que quelqu’un a dit “c’est urgent”. Parce que les données disent que le budget est épuisé.
Error Budget Burn Rate
| Burn Rate | Interprétation |
|---|---|
| 1 | Budget consommé au rythme prévu (30 jours) |
| 6 | Budget épuisé en 5 jours |
| 14.4 | Budget épuisé en 2 jours |
Multi-Window Alerting
L’approche standard pour éviter les faux positifs.
1groups:
2 - name: slo_alerts
3 rules:
4 - alert: SLOBudgetBurnCritical
5 expr: |
6 (
7 sum(increase(http_server_request_errors_total[1h]))
8 / sum(increase(http_server_requests_total[1h]))
9 ) > (14.4 * (1 - 0.999))
10 and
11 (
12 sum(increase(http_server_request_errors_total[5m]))
13 / sum(increase(http_server_requests_total[5m]))
14 ) > (14.4 * (1 - 0.999))
15 for: 2m
16 labels:
17 severity: critical
18 annotations:
19 summary: "SLO budget burning at 14.4x rate"Pourquoi deux fenêtres ? Un spike bref déclenche la fenêtre 5min mais pas la fenêtre 1h → pas d’alerte critique inutile. Une dégradation lente apparaît dans la fenêtre 6h même si aucune fenêtre 30min ne semble alarmante.
C’est le multi-window qui t’empêche de te faire réveiller pour rien à 3h du matin.
Corrélation : le workflow idéal
Voilà comment ça devrait fonctionner :
- Prometheus alerte sur les métriques RED — taux d’erreur ou p99 au-dessus du SLO
- L’alerte lie à un dashboard Grafana avec exemplars activés
- L’on-call clique sur un exemplar et lit la trace dans Tempo
- Depuis la trace, jump aux logs corrélés dans Loki
Deux clics de “quelque chose est lent” à “ce span a pris 1.8s sur l’appel gRPC payments”
C’est ça, la corrélation. Pas du grep. Pas du devinage. Du clic.
Exemplars : le pont métriques ↔ traces
Un exemplar est un trace ID attaché à un échantillon de métrique. Un point sur ton histogramme de latence connaît une requête example.
Dans Grafana, ça se traduit par des losanges cliquables sur les graphiques. Tu cliques, tu ouvres la trace. Deux clics.
Service Map depuis les Traces
Le metrics-generator de Tempo produit des RED metrics et des service graphs directement depuis les spans. Pas besoin d’instrumenter deux fois.
Résultat : une vue de qui appelle qui, dérivée du trafic réel. Pas d’un diagramme d’architecture dessiné il y a 6 mois qui est déjà faux.
Dual-Layer Observability
L’observabilité 2.0 couvre deux couches :
Couche Application
| Signal | Mesure | Outil |
|---|---|---|
| Latence utilisateur | P50/P95/P99 | Prometheus |
| Taux d’erreur | % 5xx | Prometheus |
| Débit | Requêtes/sec | Prometheus |
| Traces | Chemin complet | Tempo |
| Logs métier | Événements structurés | Loki |
Couche Réseau/Infrastructure
| Signal | Mesure | Outil |
|---|---|---|
| Latence réseau | RTT, jitter | Cilium Hubble / eBPF |
| DNS | Temps de résolution | CoreDNS metrics |
| TLS | Handshake time | Prometheus |
| Health checks | Disponibilité | Prometheus |
| K8s events | Pods lifecycle | event-exporter → Loki |
La clé : Les deux couches partagent les mêmes service names et namespace labels. Quand une alerte réseau se déclenche, tu peux jumper aux métriques application et vice versa.
Observabilité as Code
Pas de dashboards exportés depuis l’UI qui disparaissent quand le pod Grafana redémarre.
Dashboards en Git
Grafonnet (Jsonnet) ou JSON brut, versionné dans Git. Déploiement via CI/CD ou Grafana Operator.
Alertes en YAML
1groups:
2 - name: api-service
3 rules:
4 - alert: ErrorBudgetBurnRateFast
5 expr: |
6 (
7 rate(http_requests_total{status=~"5.."}[1h]) /
8 rate(http_requests_total[1h])
9 ) > 14.4 * 0.001
10 for: 5m
11 labels:
12 severity: critical
13 team: platform
14 annotations:
15 summary: "Fast error budget burn: {{ $value | humanizePercentage }}"
16 runbook: "https://runbooks.example.com/api-high-error-rate"Recording Rules
1groups:
2 - name: slo_computations
3 interval: 30s
4 rules:
5 - record: slo:availability:ratio_30d
6 expr: |
7 1 - (
8 sum(increase(http_server_request_errors_total[30d]))
9 /
10 sum(increase(http_server_requests_total[30d]))
11 )
12
13 - record: slo:availability:error_budget_remaining
14 expr: |
15 1 - (
16 (1 - slo:availability:ratio_30d)
17 /
18 (1 - 0.999)
19 )Les erreurs qui tuent
Erreur n°1 : Prometheus retention à 30+ jours
Mets retention=30j, remplis le volume EBS, Prometheus crash. “Mais pourquoi ça crash ?”
Parce que Prometheus n’est pas une base de données. Rétention courte locale (24-48h) + stockage long terme (Thanos/Mimir). Arrête de te palucher.
Erreur n°2 : Pas de cardinality limits dans Loki
Un mauvais service ship les noms de pods comme labels. L’chunk index explose. Les requêtes sont lentes pour tout le monde.
Limites de cardinality par tenant. Production 90j, staging 14j, dev 3j. Et surveille ta cardinalité.
Erreur n°3 : OTLP déployé sans sampling
Tracing déployé, pas de sampling. Le coût de stockage explose. L’équipe éteint le tracing. “Le tracing c’est trop cher.”
Non. Tu as pas configuré le sampling. Configurer le sampling jour 1. Head-based au SDK + tail-based au gateway.
Erreur n°4 : Grafana auth admin/admin
Vu en production. Sérieusement. Configure OIDC avant qu’il n’y ait des dashboards.
Erreur n°5 : Pas de dashboards en Git
Dashboards exportés depuis l’UI, perdus quand le pod redémarre. “Mais où est passé mon dashboard ?”
GitOps avec Grafana Operator. Les dashboards vivent dans Git. Point.
Erreur n°6 : Alertes sans owner ni runbook
Alerte qui tire. Personne sait quoi faire. “On a reçu l’alerte, on a googlé, on a restart le service.”
Chaque alerte a un owner, un runbook, et un lien SLO. Sinon, elle n’existe pas.
Sizing de la stack
Pour un cluster de 20 nodes, 100 pods :
| Composant | CPU | Memory | Storage |
|---|---|---|---|
| Prometheus | 500m | 3 Gi | 50 Gi (15j) |
| Alertmanager | 50m | 128 Mi | 2 Gi |
| Grafana | 100m | 256 Mi | 5 Gi |
| Loki | 300m | 1 Gi | 100 Gi (31j) |
| Promtail/Alloy | 50m/node | 64 Mi | — |
| Tempo | 200m | 512 Mi | 20 Gi (72h) |
| OTLP Collector | 100m | 128 Mi | — |
| Total | ~2.1 CPU | ~8.5 Gi | ~177 Gi |
C’est tout. Pour 1/4 à 1/10 du coût Datadog.
Gouvernance des Error Budgets
L’error budget, c’est pas un indicateur technique. C’est un outil politique.
Budget sain :
- Ship plus vite
- Lance des expériences chaos
- Déploie le vendredi
Budget épuisé :
- Freeze feature work
- Priorise la fiabilité
- Reporte les migrations risquées
Ça termine l’éternel argument entre product et SRE. Le data décide. Pas l’opinion.
La policy simple
Expose le burn rate sur un dashboard partagé. Écris une policy dans le handbook :
“Deux mois consécutifs d’épuisement du budget déclenchent un sprint fiabilité.”
C’est tout. Pas besoin d’un framework de gouvernance à 50 pages. Une règle claire, partagée, appliquée.
Pour démarrer
- Un seul service d’abord — Instrumente un service avec OTLP, exporte vers un collector, définis 1-2 SLIs
- Observe une semaine — Vérifie que les métriques matchent ton intuition
- Puis expand — Le rollout sur 30 services ira beaucoup plus vite
Checklist de démarrage
Technique :
- OTLP Collector déployé (agent + gateway)
- Prometheus avec recording rules et alerting rules SLO
- Loki avec limits de cardinalité
- Tempo avec tail-based sampling
- Grafana avec corrélation traces ↔ logs ↔ metrics
- Dashboards en Git
Organisationnel :
- SLIs définis pour chaque service user-facing
- SLOs documentés et partagés
- Error budget policy écrite
- Chaque alerte a un owner, un runbook, un lien SLO
Mot de la fin
Observabilité 2.0, c’est pas plus de dashboards. C’est de meilleurs dashboards. C’est pas plus d’alertes. C’est de meilleurs alertes. C’est pas plus d’outils. C’est de meilleurs outils.
OpenTelemetry comme plan de données. SLOs comme contrat. Error budgets comme gouvernance. Corrélation entre signaux en deux clics.
Et surtout : arrête de traiter l’observabilité comme un projet. C’est un produit. Il a des utilisateurs (les devs, les SREs), un roadmap, et des métriques d’adoption. Si personne regarde tes dashboards, c’est que tes dashboards sont pourris. Pas que les devs sont cons.
Commence par un service. Définis un SLO. Active les exemplars. Et surtout : mesure avant d’ajouter de la complexité. Parce que la complexité, elle se paie. En debugging. En maintenance. En nuits blanches à 3h du matin.
See ya space-cowboy!