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.


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.

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 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.


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

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.

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.


Le OTLP Collector est le composant le plus critique. Il reçoit, traite, et exporte la télémétrie.

┌─────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│      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.

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.

  • < 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

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.

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.

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é.

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

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.


Voilà comment ça devrait fonctionner :

  1. Prometheus alerte sur les métriques RED — taux d’erreur ou p99 au-dessus du SLO
  2. L’alerte lie à un dashboard Grafana avec exemplars activés
  3. L’on-call clique sur un exemplar et lit la trace dans Tempo
  4. 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.

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.

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.


L’observabilité 2.0 couvre deux couches :

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
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.


Pas de dashboards exportés depuis l’UI qui disparaissent quand le pod Grafana redémarre.

Grafonnet (Jsonnet) ou JSON brut, versionné dans Git. Déploiement via CI/CD ou Grafana Operator.

 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"
 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          )

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.

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é.

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.

Vu en production. Sérieusement. Configure OIDC avant qu’il n’y ait des dashboards.

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.

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.


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.


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.

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.


  1. Un seul service d’abord — Instrumente un service avec OTLP, exporte vers un collector, définis 1-2 SLIs
  2. Observe une semaine — Vérifie que les métriques matchent ton intuition
  3. Puis expand — Le rollout sur 30 services ira beaucoup plus vite

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

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!