👁️ Observabilité
Logs, Metrics, Traces - Les 3 Piliers
🏎️ Analogie : Le Tableau de Bord F1
Le Monitoring vous dit "Le moteur fume" (C'est cassé).
L'Observabilité vous permet de demander "Pourquoi ?" en regardant la télémétrie complète (Pression d'huile, température, historique des 10 dernières minutes).
⚠️ Rappel : Metrics First !
Ne basez pas vos alertes critiques sur l'analyse de texte de vos Logs. Règle d'or : Les Metrics pour alerter, les Logs pour débugger. Traiter 10 000 lignes de logs par seconde coûte très cher en CPU et stockage ; lire 1 chiffre de metric coûte presque rien.
📖 Observabilité : Illuminer la Boîte Noire
Dans un système monolithique simple, un log suffit. Dans un cluster Kubernetes avec 200 microservices, c'est impossible. L'observabilité est la capacité de comprendre l'état interne d'un système uniquement en regardant ses sorties (Metrics, Logs, Traces).
On passe du monitoring Réactif ("Tiens, ça a crashé") à l'observabilité Proactive ("La latence monte sur le service X, ça va bientôt saturer").
💡 Le saviez-vous ? Les 4 Golden Signals
Google a défini dans son livre SRE les 4 signaux d'or du monitoring que tout dashboard devrait avoir :
- Latency : Temps de réponse (ms).
- Traffic : Nombre de requêtes/sec.
- Errors : Taux de succès vs échec.
- Saturation : Utilisation des ressources (CPU, RAM, Disque).
🏛️ A. Les 3 Piliers
Logs
Quoi ? Événements textuels horodatés
Usage : Debugging, audit trail
Outils: ELK, Loki, CloudWatch
Metrics
Quoi ? Chiffres agrégés dans le temps
Usage : Alerting, dashboards
Outils: Prometheus, Datadog
Traces
Quoi ? Suivi d'une requête multi-services
Usage : Latency, bottlenecks
Outils: Jaeger, OpenTelemetry
🛠️ B. Stacks Populaires
📊 Les 3 Piliers : Quand utiliser quoi ?
📜 Logs (Événements)
- Granularité : Haute (détails précis).
- Coût : Élevé (stockage massif).
- Usage : "Pourquoi cette requête spécifique a échoué ?"
🕵️ Traces (Parcours)
- Granularité : Contextuelle (multi-services).
- Coût : Moyen (échantillonnage nécessaire).
- Usage : "Où est passée la seconde de latence entre A et B ?"
📊 Cas d'étude : Uber - Gérer 500 millions de métriques
Contexte : En grandissant, Uber a saturé toutes les solutions de métriques existantes (Graphite, Prometheus). Ils avaient besoin d'une base de données de séries temporelles (TSDB) capable de scaler horizontalement à l'infini.
Transformation :
- M3 Project : Ils ont créé leur propre stack open-source "M3" pour agréger et stocker les métriques.
- Distributed Tracing : Création de Jaeger (donné à la CNCF) pour suivre chaque course Uber à travers des milliers de microservices Go et Java.
- Adaptive Sampling : On ne garde pas 100% des traces (trop cher), mais 100% des traces en erreur et 1% des traces réussies.
Résultat : Uber peut détecter une anomalie sur le prix ou la disponibilité des chauffeurs en moins de 10 secondes partout dans le monde.
🔄 À Retenir - Observability Mastery
- Don't Log Everything : Le stockage des logs coûte cher. Filtrez à la source.
- Tagging is King : Une métrique ou un log sans tags (env, service, version) est inutile.
- Dashboards Actionnables : Un dashboard doit répondre à "Est-ce que ça marche ?" pas "Regarde ces jolis graphs".
- OpenTelemetry : Utilisez le standard ouvert OTel pour ne pas être bloqué chez un fournisseur (Lock-in).
🌐 C. OpenTelemetry - Le Standard Unifié
OpenTelemetry (OTel) est le standard CNCF (graduated project) pour l'instrumentation, la collecte et l'export de télémétrie (logs, metrics, traces). C'est la fusion de OpenTracing + OpenCensus.
Problème résolu : Avant OTel, chaque vendor (Datadog, New Relic, Jaeger) avait son propre SDK. Changer de vendor = réécrire toute l'instrumentation. OTel = vendor-neutral.
Architecture d'observabilité unifiée via OpenTelemetry. Le Collector centralise, transforme et route la télémétrie vers les backends appropriés.
📊 Architecture OTel
- Instrumentation : SDKs dans l'app (auto ou manuel)
- Collector : Agent qui reçoit, transforme, exporte
- Exporters : Envoie vers Jaeger, Prometheus, Datadog, etc.
- Context Propagation : Trace ID suit la requête partout
receivers: otlp: # Reçoit traces/metrics via gRPC protocols: grpc: endpoint: 0.0.0.0:4317 processors: batch: # Agrège avant export memory_limiter: limit_mib: 512 exporters: jaeger: endpoint: jaeger:14250 prometheus: endpoint: prometheus:9090
from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter # Setup tracer trace.set_tracer_provider(TracerProvider()) tracer = trace.get_tracer(__name__) # Export vers Collector otlp_exporter = OTLPSpanExporter(endpoint="localhost:4317") span_processor = BatchSpanProcessor(otlp_exporter) trace.get_tracer_provider().add_span_processor(span_processor)
Head-based : Décision au début de la trace (1% de tout)
Tail-based : Décision à la fin (100% des erreurs, 1% du succès)
Tail-based est plus intelligent mais plus coûteux en compute.
🔬 D. eBPF for Observability
eBPF (extended Berkeley Packet Filter) permet d'exécuter du code dans le kernel Linux sans modifier le kernel. C'est révolutionnaire pour l'observabilité : zero instrumentation.
🦅 Pixie (eBPF-based Observability)
Observabilité automatique de K8s sans changer une ligne de code.
- Capture automatique HTTP/gRPC/MySQL/Postgres requests
- Cartes de dépendances générées automatiquement
- Flamegraphs CPU sans profiler SDK
- Deploy :
kubectl apply -f pixie.yaml
🔍 Avantages eBPF
- Zero overhead : Pas de sidecars, pas de SDK
- Language-agnostic : Fonctionne avec Java, Go, Rust, C++
- Kernel-level visibility : Voit TOUT (syscalls, network packets)
- Security : Falco utilise eBPF pour détecter intrusions
eBPF ne capture pas le contexte business (user ID, transaction ID). Pour cela, vous devez quand même instrumenter manuellement avec OTel ou des logs structurés.
🎯 E. SLI/SLO/Error Budgets
📏 SLI (Indicator)
Quoi ? Métrique quantifiable de la qualité du service.
Exemples : Latency P99, Success rate, Throughput
Mesure CE QUI SE PASSE réellement.
🎯 SLO (Objective)
Quoi ? Target pour un SLI sur une période.
Exemples : "99.9% des requêtes < 200ms sur 30 jours"
Définit CE QU'ON VEUT atteindre.
📜 SLA (Agreement)
Quoi ? Contrat légal avec pénalités financières.
Exemples : "99.95% uptime ou remboursement"
Engage la RESPONSABILITÉ juridique.
💰 Error Budget
Si SLO = 99.9% uptime, alors Error Budget = 0.1% downtime autorisé = 43 minutes/mois.
- Budget consommé → Freeze features, focus stabilité
- Budget restant → OK pour déployer features risquées
- Alignement Dev/SRE : même métrique, même objectif
Error Budget = (1 - SLO) × périodeEx: (1 - 0.999) × 30 jours × 24h × 60min = 43.2 minutes
# Alerte si on consomme Error Budget trop vite alert: ErrorBudgetBurn expr: | ( 1 - sum(rate(http_requests_total{status=~"2.."}[1h])) / sum(rate(http_requests_total[1h])) ) > (14.4 * (1 - 0.999)) # 14.4x = consomme budget en 2h au lieu de 30j for: 5m labels: severity: critical annotations: summary: "Burning error budget 14x faster"
💸 F. Cardinality & Cost Management
Cardinality = nombre de combinaisons uniques de tags (labels). C'est LE problème #1 qui fait exploser les coûts de monitoring.
Métrique :
http_requests{service, method, path, user_id, request_id}Si 10 services × 5 methods × 1000 paths × 10M users × infinité request_id = 🔥💸
Solution : JAMAIS mettre user_id ou request_id en tag. Utiliser des logs pour ça.
✅ Cardinality Best Practices
- Low cardinality tags OK : env, service, region, status_code
- High cardinality tags NO : user_id, request_id, timestamp
- Agrégation intelligente : /users/123 → /users/:id
- Monitoring de cardinality : Alerter si spike
| Stratégie | Coût | Granularité | Use Case |
|---|---|---|---|
| 100% des métriques | $$$$ | Max | Dev/Staging uniquement |
| Sampling (10%) | $$ | Moyen | Production standard |
| Tail-based (erreurs only) | $ | Intelligent | Production optimisé |
| Retention 7j vs 90j | $ vs $$$ | - | Compliance requirements |
🕸️ G. Distributed Tracing Avancé
# Headers HTTP propagés automatiquement traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01 │ │ │ │ │ └─ Trace ID (128-bit) │ └─ Sampled? │ └─ Span ID (64-bit) └─ Version # Chaque service ajoute son span à la trace GET /api/orders → create_span("fetch_order") { call payment_service # Passe traceparent call inventory_service # Passe traceparent }
🏷️ Span Tags & Baggage
- Tags : Metadata du span (http.method, db.statement)
- Baggage : Key-value propagés à TOUS les spans enfants
- Use case baggage : user_tier (premium/free) pour sampling
- Warning : Baggage augmente taille des headers → latency
🏢 H. Observability Platforms Comparison
| Platform | Type | Forces | Faiblesses |
|---|---|---|---|
| Datadog | Commercial (SaaS) | All-in-one, APM excellent, UX top | Très cher (cardinality pricing) |
| Grafana Stack | Open-source | Loki (logs), Tempo (traces), Mimir (metrics), gratuit | Self-hosted = ops overhead |
| Elastic (ELK) | Open-core | Search puissant, mature, large écosystème | Ressource hungry (Java heap) |
| New Relic | Commercial (SaaS) | Ingestion illimitée, pricing par user | Query language moins flexible |
| Honeycomb | Commercial (SaaS) | High-cardinality native, best pour debug | Focus traces uniquement |
📊 Cas d'étude : Shopify - Migration vers OpenTelemetry
Contexte : Shopify utilisait un mix de Datadog SDK + custom instrumentation. Changer de vendor = 6 mois de refactoring. Inacceptable.
Migration OTel :
- Phase 1 : Deploy OTel Collector en sidecar (sans changer app code)
- Phase 2 : Auto-instrumentation pour Ruby/Go (80% du backend)
- Phase 3 : Migration des custom spans vers OTel SDK
- Phase 4 : Multi-vendor export (Datadog + Honeycomb pour A/B test)
Résultat : Vendor-agnostic. Peut changer de backend observability sans toucher au code. Coût réduit de 40% en optimisant sampling.
📊 Cas d'étude : Airbnb - Cardinality Explosion Incident
Contexte : Un développeur a ajouté un tag listing_id (7M valeurs
uniques)
à une métrique de latency.
Impact immédiat :
- Prometheus TSDB saturée → toutes les queries timeoutent
- Datadog facture 10M nouvelles métriques × $0.05 = $500K/an projeté
- Alertes cassées → équipes aveugles pendant 3h
Fix : Tag listing_id supprimé. Remplacé par aggregation dans logs.
Ajout de cardinality guard : CI bloque si une métrique a >1000 combinaisons de
tags.
Leçon : La cardinality peut détruire votre observability ET votre budget. Reviewez les tags comme du code critique.
🔄 À Retenir - Observability Mastery
- Don't Log Everything : Le stockage des logs coûte cher. Filtrez à la source.
- Tagging is King : Une métrique ou un log sans tags (env, service, version) est inutile.
- Dashboards Actionnables : Un dashboard doit répondre à "Est-ce que ça marche ?" pas "Regarde ces jolis graphs".
- OpenTelemetry : Utilisez le standard ouvert OTel pour ne pas être bloqué chez un fournisseur (Lock-in).
- eBPF = Future : Observabilité zero-instrumentation au niveau kernel (Pixie, Falco).
- SLO/Error Budgets : Alignez Dev et SRE sur des métriques business objectives.
- Cardinality = Enemy #1 : High-cardinality tags explosent les coûts et cassent les TSDB.
- Sampling intelligent : Tail-based sampling = 100% erreurs + 1% succès = best ROI.
# Taux d'erreurs HTTP (5xx) rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) # Latence P99 histogram_quantile(0.99, rate(http_duration_seconds_bucket[5m])) # CPU usage par pod sum by(pod)(rate(container_cpu_usage_seconds_total[5m]))
🚨 Alerting Best Practices
- SLO-based : Alerter sur Error Budget burn rate
- Pas trop d'alertes : Alert fatigue = tout ignorer
- Runbooks : Chaque alerte → action claire
- Escalation : PagerDuty, OpsGenie
🛑 Troubleshooting : Prometheus ne remonte plus mes métriques
- Symptôme : Vos graphes Grafana sont vides ou affichent "No Data", et vos requêtes PromQL ne renvoient rien pour un service donné.
- Diagnostic : En général, l'application a planté, ou l'endpoint
/metricsn'est plus accessible (firewall, mauvaise configuration du ServiceMonitor). Allez dans l'UI de Prometheus > Status > Targets. - Remède :
1. Si la target est en
DOWN: Vérifiez les logs réseau ou l'état du pod de l'application.
2. Si la target est absente : Vérifiez les annotations (ex:prometheus.io/scrape: "true") ou le manifesteServiceMonitor/PodMonitordans Kubernetes.