đ¶ Partie 4 : Pilier 3 - Log Management (Deep Dive)
Collecte (Fichier, TCP, Docker/K8s), Pipelines de Parsing (Grok/JSON), Facets, Recherche & Corrélation APM.
Qu'est-ce que le Log Management ?
Pilier 3. Les événements individuels (texte). (Metrics = Agrégats).
Logs EventsĂtape 1 : Activation & Collecte
logs_enabled: true. (Méthodes : File, stdout, TCP/UDP).
Collecte (Exemples)
conf.d/ (VM), Autodiscovery (K8s), Handler TCP (Python).
Ătape 2 : Pipelines de Parsing
Transformer le texte brut en JSON structuré. (source:nginx).
Parsing : Grok vs JSON
RĂšgle d'or : Loguez en JSON ! (Ăvite le Grok/Regex coĂ»teux).
JSON GrokFacets vs Attributs
Attribut (stocké) vs Facet (indexé, filtrable).
Facets @attributeĂtape 3 : Log Explorer (Recherche)
service:api status:error "payment failed". (Full-text + Facets).
Log Patterns
Regroupement (ML) des logs similaires (User {id} login).
Ătape 4 : CorrĂ©lation Logs <-> APM
Le "Saint Graal". Injection trace_id. (Pivot "Log" -> "Trace").
Concepts Avancés (Coût)
Log-based Metrics, Archiving & Rehydrating (S3).
Log-based Metrics ArchivingCheat-sheet (Logs)
Config Agent, Syntaxe de recherche, Corrélation.
cheat ConfigLes Métriques (Partie 2) sont des agrégats (ex: "500 erreurs par minute"). Les Logs sont les événements individuels, textuels, qui composent cet agrégat (ex: "Ligne 500: ERROR: Connection refused for user 'admin'").
Le Log Management de DataDog est un service SaaS (similaire Ă Splunk, ELK/Elastic Stack, ou Grafana Loki) qui s'occupe de :
- Collecter : Agréger les logs de milliers de sources (fichiers, conteneurs, cloud).
- Processer (Parser) : Transformer le texte brut (
"GET / 200") en données structurées ({method: "GET", path: "/", status: 200}). - Indexer : Rendre ces données interrogeables (Search).
- Corréler : Lier un log à sa Métrique et sa Trace APM (le plus important).
La collecte des logs est (presque) toujours effectuĂ©e par l'Agent DataDog. Elle doit d'abord ĂȘtre activĂ©e globalement sur l'Agent.
# (datadog.yaml)
logs_enabled: true
# (Variable d'environnement Docker/K8s)
# DD_LOGS_ENABLED="true"
| Méthode de Collecte | Description | Cas d'usage |
|---|---|---|
| File (Tailing) | (La plus simple) L'Agent "surveille" (tail) un fichier (ex: /var/log/nginx.log). | Serveurs "legacy" (VMs), applications qui n'écrivent pas sur stdout. |
Docker/K8s (stdout) | (Standard Moderne) L'Agent collecte automatiquement les flux stdout/stderr de TOUS les conteneurs. | Microservices, Kubernetes. |
| TCP / UDP | L'Agent ouvre un port (ex: 10518) et écoute les logs (ex: Syslog, Handlers applicatifs). | Routeurs, Firewalls, Applications (Python/Java logging). |
| API / Lambda | (Sans Agent) Envoi direct Ă l'API DataDog. | AWS Lambda (via l'extension DD), scripts "serverless". |
1. Collecte par Fichier (conf.d/nginx.d/conf.yaml)
Configuration pour "suivre" un fichier log NGINX (sur une VM).
# (La section 'logs' est ajoutée à l'intégration NGINX)
logs:
- type: file
path: /var/log/nginx/access.log
# (Tags cruciaux pour la corrélation)
service: frontend-web
source: nginx # (Ceci DĂCLENCHE le "pipeline de parsing" NGINX)
- type: file
path: /var/log/nginx/error.log
service: frontend-web
source: nginx
2. Collecte K8s (stdout via Autodiscovery)
L'Agent K8s écoute les stdout. On utilise des Annotations sur le Deployment.yaml pour "tagguer" ces logs.
# (Extrait de mon-api.deployment.yaml)
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-python-api
spec:
template:
metadata:
annotations:
# (Instructions pour l'Agent DataDog (Autodiscovery))
# (Cherche les conteneurs nommés "my-api-container")
"ad.datadoghq.com/my-api-container.logs": |
[
{
"service": "api-users",
"source": "python"
}
]
spec:
containers:
- name: my-api-container
image: my-api:1.2.3
# (L'app logue en JSON sur stdout)
3. Collecte TCP (Handler Python)
Si l'application ne peut pas écrire sur stdout ou fichier, on peut configurer le logger (ex: Python) pour envoyer les logs en TCP à l'Agent local (localhost:10518).
# (Python: logging.conf)
'handlers': {
'datadog': {
'class': 'logging.handlers.SocketHandler',
'host': 'localhost', // (L'Agent DD local)
'port': 10518, // (Port TCP configuré dans l'Agent)
},
},
'loggers': { 'myapp': { 'handlers': ['datadog'], ... } }
# (datadog.yaml)
logs_config:
- type: tcp
port: 10518
service: myapp-backend
source: python
Les logs arrivent sous forme de texte brut ("raw"). C'est illisible et inutilisable pour les filtres.
Un Log Pipeline (Pipeline de Traitement) est une série d'étapes (cÎté DataDog) pour **transformer** ce texte en **JSON structuré**.
Diagramme : Pipeline de Log (Simplifié)
(Log Brut Reçu)
"10.1.2.3 - - [10/Oct/2025:13:55:36] "GET /api/v1/user HTTP/1.1" 200 512"
|
âŒ
+------------------------------------------------+
| Pipeline (Matching 'source:nginx') |
+------------------------------------------------+
| 1. Parser (Grok) |
| (Extrait "GET", "/api/v1/user", 200) |
| | |
| ⌠|
| 2. Remapper (Attributs) |
| ('http.status_code' = 200) |
| ('http.method' = "GET") |
| | |
| ⌠|
| 3. Create Facets (Indexation) |
| (Rendre '@http.status_code' filtrable) |
+------------------------------------------------+
|
âŒ
(Log Structuré (JSON))
{
"message": "10.1.2.3 - ...",
"http": {
"status_code": 200,
"method": "GET",
"url_path": "/api/v1/user"
},
"service": "frontend-web",
...
}
La RĂšgle d'Or : Si vous le pouvez, loguez en JSON !
| Méthode | Description | Performance |
|---|---|---|
| JSON Logging (Recommandé) | Votre application logue directement en JSON (via une lib json-logging). DataDog parse le JSON automatiquement. | Rapide (Pas de Regex). |
| Grok Parsing (Legacy) | DataDog utilise des Regex (Grok) complexes pour "casser" le texte brut (ex: logs NGINX, Syslog). (Ex: %{ip:network.client.ip}). | Lent (Coûteux en CPU cÎté DataDog). |
C'est un concept clé de DataDog (et source de confusion).
- Attribut (JSON) : Une donnée extraite du log (ex:
user.id: 123). Elle est stockĂ©e (visible dans le JSON du log), mais on ne peut pas filtrer (@user.id:123) ou grouper dessus (group by @user.id). - Facet (Facette) : Un attribut que vous avez **promu** (dans l'UI DataDog) pour ĂȘtre **indexĂ©**. Permet le filtrage, le
GROUP BY, et la recherche.
Les tags (env, service, host) et les attributs clés (status, source) sont des Facets par défaut. Vous devez manuellement créer des Facets pour vos attributs custom (ex: user.id, cart.id) pour pouvoir les utiliser dans les recherches (4.7) ou les dashboards.
C'est l'interface (UI) pour rechercher, filtrer et analyser les logs structurés. La recherche est basée sur le "full-text" et les Facets (@).
| RequĂȘte de Recherche | Ce qu'elle trouve |
|---|---|
"payment failed" | Logs contenant "payment failed" (Full-text). |
service:api-payment | Logs taggués avec service:api-payment. |
status:error | Logs (de n'importe quel service) avec le statut "error". |
env:prod service:api-users @http.status_code:500 | Logs du service 'api-users' en 'prod' qui sont des erreurs HTTP 500. |
@user.id:12345 | Logs (tous services) concernant l'utilisateur 12345 (nécessite un Facet custom @user.id). |
-@http.status_code:200 | Logs qui ne sont PAS des 200 OK. |
DataDog utilise le ML "on-the-fly" pour regrouper les logs similaires. Au lieu de voir 1 million de lignes :
INFO: User 123 failed login (IP: 1.2.3.4)
INFO: User 456 failed login (IP: 5.6.7.8)
INFO: User 101 failed login (IP: 9.0.1.2)
... (1 million de fois)
L'onglet "Patterns" vous montrera :
INFO: User {*} failed login (IP: {*}) (Count: 1,000,000)
C'est vital pour détecter une "explosion" d'un nouveau type d'erreur (ex: FATAL: Cannot connect to DB {*}).
C'est la fonctionnalitĂ© la plus puissante, qui justifie d'avoir APM (Traces) et Logs dans la mĂȘme plateforme.
Comme vu en Partie 3 (APM), si dd-trace (APM) est activé, il **injecte automatiquement** le trace_id et span_id actuels dans vos logs (s'ils sont en JSON, ou via DD_LOGS_INJECTION=true).
Exemple (Log Python JSON)
{
"timestamp": "2024-10-27T10:30:05Z",
"level": "ERROR",
"message": "Payment failed for user 123",
"service": "api-payment",
// (Injecté par dd-trace)
"dd": {
"trace_id": "4567890123456",
"span_id": "9876543210987"
}
}
Résultat (Pivot) :
1. (Vue "Trace" -> "Logs") : Vous regardez un Flame Graph (Trace APM) d'une requĂȘte /checkout lente. L'onglet "Logs" vous montre uniquement les logs (y compris l'erreur "Payment failed") de *cette requĂȘte prĂ©cise*.
2. (Vue "Log" -> "Trace") : Vous trouvez ce Log d'erreur. Vous cliquez sur le trace_id. DataDog vous amÚne au Flame Graph complet, vous montrant ce qui s'est passé *avant* et *aprÚs* l'erreur.
Les Logs coûtent cher à indexer (Haute ingestion, haute rétention).
Log-based Metrics (Métriques basées sur les Logs)
Vous ne voulez peut-ĂȘtre pas *indexer* 1 Milliard de logs NGINX (status:200), mais vous voulez *compter* combien il y en a (une MĂ©trique).
Vous pouvez crĂ©er une "Log-based Metric" : DataDog scanne le log Ă l'ingestion, incrĂ©mente un compteur (nginx.hits {status:200}), puis (optionnellement) jette le log (s'il est configurĂ© pour ne pas ĂȘtre indexĂ©). C'est beaucoup moins cher.
Archiving (Archivage) & Rehydrating (Réhydratation)
Garder les logs "Hot" (indexés, interrogeables) coûte cher (ex: rétention 15 jours).
Vous pouvez (vous devez) **Archiver** (Archiving) tous vos logs (bruts) vers un stockage "Froid" (Cold Storage) (ex: Amazon S3, Google GCS). C'est peu coûteux.
Si vous avez besoin d'enquĂȘter (ex: audit 6 mois plus tard), vous utilisez **Rehydrate from Archive** (RĂ©hydrater) pour rĂ©-importer les logs de S3 vers DataDog (Log Explorer).
Activation (datadog.yaml)
logs_enabled: true
Collecte Fichier (conf.d/)
# (ex: java.d/conf.yaml)
logs:
- type: file
path: /var/log/my-app/app.log
service: my-java-app
source: java
Collecte K8s (Annotation)
# (deployment.yaml)
metadata:
annotations:
"ad.datadoghq.com/my-container.logs": |
[
{"service": "my-java-app", "source": "java"}
]
Syntaxe de Recherche
# 1. Full-text
"Error 500"
# 2. Facets (Tags)
env:prod service:api-payment
# 3. Facets (Attributs parsés)
@http.status_code:500
@user.id:12345
# 4. Multi-filtres
service:api-payment status:error (user:bob OR "timeout")
Corrélation APM (Python)
# (Activer l'injection auto)
export DD_LOGS_INJECTION="true"
# (Lancer l'app)
dd-trace-run python app.py
