Project Oxygen & Ideo-LabIDEO LAB Dashboard 2026

đŸ¶ Partie 6 : Projet Pratique (Full Stack)

Cas d'usage : Dépanner une application E-commerce (React + Python + K8s) en corrélant RUM, Traces, Métriques et Logs.

6.1 Moyen

Objectif & Scénario

L'alerte se déclenche : "Les clients se plaignent que le checkout est LENT !"

Projet Alerte
6.2 Moyen

Architecture de l'App Fictive

Notre stack : React (RUM), Python (APM), Postgres (Metrics), K8s (Agent).

Architecture React Python
6.3 Avancé

Configuration (Le Tagging Unifié)

Le setup (RUM, APM, K8s) qui rend la corrélation (service, env) possible.

Tagging Setup
6.4 Moyen

Étape 1 : L'EnquĂȘte (RUM)

Pivot depuis le Frontend. (click on #btn-checkout > 8000ms). Isoler le fetch.

RUM Frontend
6.5 Avancé

Étape 2 : L'EnquĂȘte (APM)

Pivot vers le Backend (Flame Graph). Isoler le Span postgres.query (7.2s).

APM Flame Graph
6.6 Avancé

Étape 3 : L'EnquĂȘte (Logs)

Pivot vers les Logs (trace_id). Confirmer le INSERT lent (WARN).

Logs Corrélation
6.7 Avancé

Étape 4 : L'EnquĂȘte (MĂ©triques)

Pivot vers la DB (service:db-postgres). Trouver le pic de postgresql.locks.

Metrics Root Cause
6.8 Moyen

Conclusion de l'EnquĂȘte

La cause racine (Root Cause) : Un access_exclusive_lock (d'un batch) bloque les INSERT.

Conclusion Action
6.9 Facile

Cheat-sheet (L'EnquĂȘte)

Le workflow de pivot : RUM -> APM -> LOGS -> METRICS.

cheat M-T-L-R
6.1 Objectif du Projet & Le Scénario
L'Objectif : L'EnquĂȘte Full-Stack

Ce projet fictif simule le scénario le plus courant (et le plus stressant) : **"Les clients se plaignent que le site est lent !"**

Notre objectif est de trouver la **cause racine (root cause)** en utilisant les 4 piliers de DataDog (RUM, Métriques, Traces, Logs), en pivotant de l'un à l'autre grùce au **Tagging Unifié**.

Le Scénario : L'Alerte (Monitor)

10:30 AM : Une alerte (Monitor DataDog) se déclenche dans Slack :

[ALERTE 🚹] P95 Checkout Latency > 8s

(Triggered)
avg(last_5m):rum.action.loading_time{env:prod, action.name:"click on #btn-checkout"} > 8000ms

(Current value: 8530ms)

Traduction : La latence p95 (ressentie par l'utilisateur) lors d'un clic sur le bouton "Payer" est supérieure à 8 secondes. C'est catastrophique.

6.2 Architecture de l'Application Fictive "E-Shop"
L'Application (sur K8s, env:prod)
ComposantTechnologieService (Tag)Monitoring DataDog
FrontendReact (Navigateur)service:web-storeRUM (@datadog/browser-rum)
API (Backend)Python (Flask)service:api-paymentAPM (dd-trace-py) + Logs (stdout)
DatabasePostgreSQLservice:db-postgres-primaryMetrics (Intégration) + Logs (File)
InfrastructureKubernetes(K8s)Agent (DaemonSet) (Metrics Host + Logs stdout)
Diagramme d'Architecture & Observabilité
(Utilisateur: Navigateur)
+-------------------------+
| App React (Client)      | --(RUM SDK)--> [DataDog SaaS]
| (service: web-store)    |
+-------------------------+
      | (fetch /api/checkout)
      | (Injecte x-datadog-trace-id)
      ▌
(Cluster Kubernetes: env:prod)
+-------------------------------------------------------------+
|                                                             |
| +-----------------------+     +---------------------------+ |
| | Pod API (Python/Flask)  |     | Pod DB (Postgres)         | |
| | (service: api-payment)|     | (service: db-postgres)    | |
| | (Logs -> stdout)      |     | (Logs -> /var/log/...)    | |
| +-----------------------+     +---------------------------+ |
| | (APM: dd-trace-py)    |     |                           | |
| +-----------------------+     +---------------------------+ |
|             | (Logs)                      | (Logs, Metrics) |
|             +-----------------------------+                 |
|                                           |                 |
| +---------------------------------------------------------+ |
| | Pod Agent DataDog (DaemonSet, 1 par NƓud)               | |
| | (Collecte stdout, /var/log, APM 8126, DogStatsD 8125)  | |
| +---------------------------------------------------------+ |
|             | (HTTPS: Métriques, Logs, Traces)            |
|             ▌                                             |
+-------------+---------------------------------------------+
              |
              ▌
    [DataDog SaaS (UI)]
    (Dashboards, APM, Logs, RUM)
            
6.3 Configuration (Le Tagging Unifié)

Pour que ce scĂ©nario fonctionne, la configuration (le **Tagging**) doit ĂȘtre parfaite (env:prod, service:...).

Frontend : RUM (React index.js)
// (index.js de l'app React)
import { datadogRum } from '@datadog/browser-rum';

datadogRum.init({
    applicationId: '...',
    clientToken: '...',
    site: 'datadoghq.eu',
    
    // (Tags unifiés)
    service: 'web-store',
    env: 'production',
    version: '2.1.0',
    
    // (Active la corrélation RUM <-> APM)
    allowedTracingOrigins: ["https://api.mon-shop.com"]
});
                
Backend : APM (Python Dockerfile)
# (Dockerfile de l'API Python)
FROM python:3.10-slim
RUN pip install dd-trace gunicorn

# (Définir les Tags (via Env Vars))
ENV DD_ENV="production"
ENV DD_SERVICE="api-payment"
ENV DD_VERSION="1.2.0"
ENV DD_LOGS_INJECTION="true" # (Injecte le trace_id dans les logs JSON !)

# (Lancer via dd-trace-run)
CMD ["dd-trace-run", "gunicorn", "app:main"]
                
Infra : K8s (Annotations Autodiscovery)
# (deployment-postgres.yaml)
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    metadata:
      annotations:
        # (Autodiscovery pour les Métriques)
        "ad.datadoghq.com/db-container.checks": |
          {
            "postgres": {
              "instances": [
                {
                  "host": "%%host%%",
                  "port": 5432,
                  "tags": ["env:production", "service:db-postgres-primary"]
                }
              ]
            }
          }
        # (Autodiscovery pour les Logs)
        "ad.datadoghq.com/db-container.logs": |
          [
            {"source": "postgresql", "service": "db-postgres-primary"}
          ]
    spec:
      containers:
      - name: db-container
        image: postgres:15
                
6.4 Étape 1 : L'EnquĂȘte (RUM)

Nous allons dans RUM > Performance > Actions et nous cliquons sur l'action click on #btn-checkout.

Le dashboard RUM confirme que l'action est lente (8000ms). Il décompose cette latence :

  • Frontend (JS) : 50ms (Le JS React est rapide).
  • Backend (RĂ©seau) : 7950ms (Le goulot d'Ă©tranglement est cĂŽtĂ© serveur).

Nous cliquons sur l'onglet "Resources" (Ressources) de cette action RUM. Nous voyons la requĂȘte rĂ©seau coupable :
POST https://api.mon-shop.com/api/v1/checkout (Durée: 7950ms)

GrĂące Ă  la corrĂ©lation RUM <-> APM (configurĂ©e en 6.3), nous voyons un bouton "View Trace" (Voir la Trace) Ă  cĂŽtĂ© de cette requĂȘte.

Pivot : RUM -> APM
6.5 Étape 2 : L'EnquĂȘte (APM)

En cliquant sur "View Trace", nous pivotons de RUM (Frontend) vers **APM (Backend)**. DataDog nous montre le Flame Graph (diagramme en cascade) de *cette* requĂȘte spĂ©cifique (trace_id: abc-123).

Diagramme (Flame Graph APM)
Service: web-store (RUM) (8000ms)
|
+--- Service: api-payment (Python/Flask) (7950ms) --------------------------------+
|    |                                                                         |
|    +-- flask.request (Span) ------------------------------------------------+ |
|    |   |                                                                   | |
|    |   +-- flask.auth (Span) (50ms)                                        | |
|    |   |                                                                   | |
|    |   +-- (Temps "inconnu" : 300ms)                                       | |
|    |   |                                                                   | |
|    |   +-- api.payment.charge (Span Custom) (7500ms) ---------------------+ | |
|    |   |   |                                                             | | |
|    |   |   +-- http.request (Stripe API) (Span) (200ms)                  | | |
|    |   |   |                                                             | | |
|    |   |   +-- (Temps "inconnu" : 100ms)                                 | | |
|    |   |   |                                                             | | |
|    |   |   +-- postgres.query (Span) (7200ms) --------------------------+ | | |
|    |   |   |                                                             | | |
|    |   |   +-------------------------------------------------------------+ | |
|    |   |                                                                   | |
|    |   +-- db.commit (Span) (50ms)                                         | |
|    |                                                                       | |
|    +-----------------------------------------------------------------------+ |
|                                                                              |
+------------------------------------------------------------------------------+
            

Diagnostic : La latence (7950ms) ne vient pas de l'API de paiement Stripe (200ms). Elle vient de notre propre base de données. Un postgres.query (dans notre Span custom api.payment.charge) prend **7.2 secondes**.

Pivot : APM -> Logs
6.6 Étape 3 : L'EnquĂȘte (Logs)

Nous cliquons sur le Span postgres.query (7200ms).

Dans le panneau du Span, l'auto-instrumentation (dd-trace-py) nous montre le Tag db.statement :
INSERT INTO orders (user_id, item, ...) VALUES (...)

Un INSERT ne devrait jamais prendre 7 secondes. Nous cliquons sur l'onglet **"Logs"** (qui est automatiquement filtré sur trace_id: abc-123 grùce à DD_LOGS_INJECTION=true).

Logs corrélés (Filtrés sur trace_id: abc-123)
(service: api-payment) INFO: User 456 checkout initiated. [dd.trace_id=abc-123]
(service: api-payment) INFO: Calling Stripe API... [dd.trace_id=abc-123]
(service: api-payment) INFO: Stripe call successful (200ms). [dd.trace_id=abc-123]
(service: api-payment) WARN: Slow query detected (7200ms) for statement: INSERT INTO orders... [dd.trace_id=abc-123]
(service: api-payment) INFO: Checkout for user 456 complete. [dd.trace_id=abc-123]
            

Diagnostic : Les logs confirment que l'INSERT est lent. Il n'y a pas d'ERROR, juste un WARN (que nous avons logué). Pourquoi un INSERT est-il si lent ? C'est probablement un **verrou (LOCK)**.

Pivot : Logs -> Métriques
6.7 Étape 4 : L'EnquĂȘte (MĂ©triques DB)

Nous pivotons vers l'infrastructure. Nous cliquons sur le Tag service:db-postgres-primary (qui était sur le Span/Log). DataDog nous amÚne au **Dashboard de l'Intégration Postgres**.

Nous regardons les métriques de la base de données (collectées par l'Agent, configuré en 6.3) au moment de l'incident :

  • postgresql.cpu.total : Normal (20%)
  • postgresql.connections : Normal (30/100)
  • postgresql.locks (groupĂ© par lock_mode) :
Widget (Timeseries) : sum:postgresql.locks{*} by {lock_mode}
(Graphique)
      |
  100 |
      |
   50 |
      |
    0 |_____________________________^_____________________________
                                  |
    (Légende)
    - access_share_lock: 30
    - row_exclusive_lock: 10
    - access_exclusive_lock: 45  (-> PIC ANORMAL !)
            

BINGO. Un pic de verrous access_exclusive_lock coĂŻncide parfaitement avec la latence.

Pivot : Métriques -> Cause Racine
6.8 Conclusion de l'EnquĂȘte

Le RUM nous a dit que les utilisateurs (Frontend) souffraient (8s).
L'APM (Trace) a isolé le problÚme sur le Backend (api-payment).
L'APM (Span) a ciblĂ© une requĂȘte INSERT spĂ©cifique (7.2s).
Les Logs (corrĂ©lĂ©s) ont confirmĂ© que cette requĂȘte Ă©tait lente, mais sans erreur.
Les Métriques (DB) ont montré la cause racine : un pic de verrous access_exclusive_lock sur Postgres.

Action (Cause Racine)

Un autre service (ex: service:reporting-batch) doit lancer un TRUNCATE ou VACUUM FULL (qui prend un verrou exclusif) sur la table orders en pleine journée (env:prod), bloquant tous les INSERT du checkout.

Sans cette corrĂ©lation M-T-L-R, le Frontend aurait blĂąmĂ© le Backend, et le Backend aurait blĂąmĂ© la DB. Avec DataDog, l'Ă©quipe SRE sait exactement quel job batch (service:reporting-batch) doit ĂȘtre dĂ©placĂ© pendant la nuit.

6.9 Cheat-sheet (Le Workflow de Dépannage)

C'est le "workflow" mental pour dépanner n'importe quel problÚme dans une stack moderne avec DataDog.

ÉtapeProduit DataDogQuestionAction
1Monitors (Alerte)"Qu'est-ce qui est cassé ?"(Notification Slack/PagerDuty)
2RUM (Frontend)"Est-ce que l'utilisateur est impacté ? Est-ce le Frontend ou le Backend ?"(Isoler la Resource (fetch) lente)
3APM (Backend)"OĂč (dans le backend) est la latence ?"(Suivre la Trace, trouver le Span lent (ex: db.query))
4Logs (Détails)"Y a-t-il une erreur ou un contexte pour ce Span ?"(Pivoter vers les Logs (trace_id), lire le WARN/ERROR)
5Metrics (Infra)"L'infrastructure (DB, Host) est-elle la cause ?"(Pivoter vers le Dashboard (service:db), trouver le pic postgresql.locks)