Logstash pour les devs - 09 - Le filtre Grok : parser n'importe quel log

Grok est LE filtre Logstash. Patterns predefinis, patterns custom, debugger en ligne et exemples Apache, Nginx, syslog.

  1. 01 Logstash pour les devs - 00 - Pourquoi Logstash existe encore en 2026
  2. 02 Logstash pour les devs - 01 - L'Elastic Stack de A a Z
  3. 03 Logstash pour les devs - 02 - Installer Logstash avec Docker en 5 minutes
  4. 04 Logstash pour les devs - 03 - Anatomie d'un pipeline Logstash
  5. 05 Logstash pour les devs - 04 - Inputs stdin et file : lire des donnees locales
  6. 06 Logstash pour les devs - 05 - Input Beats : recevoir des logs de Filebeat
  7. 07 Logstash pour les devs - 06 - Inputs HTTP, TCP et UDP : recevoir des donnees réseau
  8. 08 Logstash pour les devs - 07 - Inputs Kafka et JDBC : sources avancees
  9. 09 Logstash pour les devs - 08 - Les codecs : decoder et encoder les donnees
  10. 10 Logstash pour les devs - 09 - Le filtre Grok : parser n'importe quel log
  11. 11 Logstash pour les devs - 10 - Le filtre Dissect : parser sans regex
  12. 12 Logstash pour les devs - 11 - Le filtre Mutate : transformer les champs
  13. 13 Logstash pour les devs - 12 - Filtres Date et GeoIP : temps et geolocalisation
  14. 14 Logstash pour les devs - 13 - Filtres KV, JSON et XML : parser les formats structures
  15. 15 Logstash pour les devs - 14 - Le filtre Ruby : quand les autres ne suffisent pas
  16. 16 Logstash pour les devs - 15 - Filtres Aggregate et Metrics : correler les événements
  17. 17 Logstash pour les devs - 16 - Conditionnels et contrôle de flux
  18. 18 Logstash pour les devs - 17 - Output Elasticsearch : envoyer les donnees
  19. 19 Logstash pour les devs - 18 - Outputs file, stdout et les autres
  20. 20 Logstash pour les devs - 19 - Gerer le multiline : stack traces et logs multi-lignes
  21. 21 Logstash pour les devs - 20 - Pipelines multiples et pipeline-to-pipeline
  22. 22 Logstash pour les devs - 21 - Performance et tuning Logstash
  23. 23 Logstash pour les devs - 22 - Monitoring Logstash : metriques et alertes
  24. 24 Logstash pour les devs - 23 - Dead Letter Queue : ne plus perdre d'événements
  25. 25 Logstash pour les devs - 24 - Sécurité Logstash : SSL, auth et secrets
  26. 26 Logstash pour les devs - 25 - Debugger un pipeline Logstash
  27. 27 Logstash pour les devs - 26 - Tester ses pipelines avant la prod
  28. 28 Logstash pour les devs - 27 - Cas pratique : centraliser des logs applicatifs
  29. 29 Logstash pour les devs - 28 - Cas pratique : ETL avec Logstash et PostgreSQL
  30. 30 Logstash pour les devs - 29 - Cas pratique : enrichir des donnees en temps réel
  31. 31 Logstash pour les devs - 30 - Logstash en production : architecture et bonnes pratiques
  32. 32 Logstash pour les devs - 31 - Glossaire Logstash de A a Z

09 - Le filtre Grok : parser n'importe quel log

Ce que tu vas apprendre

  • La syntaxe Grok et comment elle fonctionne par-dessus les regex
  • Les 20 patterns built-in les plus utiles
  • Parser des logs Apache, Nginx et syslog
  • Creer tes propres patterns custom
  • Utiliser le Grok Debugger pour tester
  • Les erreurs courantes et comment les éviter

Prerequisites

  • Savoir ce qu'est un filtre Logstash (voir article 03)
  • Des bases en regex aident (mais ne sont pas obligatoires)

Grok, c'est des regex deguisees

La première fois que j'ai ouvert un pipeline Logstash en production, j'ai vu ca :

%{COMBINEDAPACHELOG}

Un mot en majuscules entre %{}. Ca ne ressemblait a rien que je connaissais. En fait, c'est juste un alias pour une regex. COMBINEDAPACHELOG est un pattern predefini qui se développé en une regex de 200 caractères.

Grok, c'est ca : une bibliothèque de regex nommees. Au lieu d'écrire (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}), tu ecris %{IP}. Au lieu de memoriser les groupes de capture, tu donnes un nom au champ directement.

La syntaxe

Pattern simple

%{PATTERN_NAME:field_name}
  • PATTERN_NAME : le nom du pattern (une regex predefinie)
  • field_name : le nom du champ dans lequel stocker le résultat

Exemple : %{IP:client_ip} matche une adresse IP et la stocke dans le champ client_ip.

Pattern sans capture

%{PATTERN_NAME}

Sans :field_name, le pattern matche mais ne capture pas dans un champ. Utile pour "consommer" du texte sans le garder.

Pattern avec type

%{PATTERN_NAME:field_name:type}

Le troisieme élément force un type : int ou float.

%{INT:status_code:int}
%{NUMBER:duration:float}

Ca évité de faire un mutate { convert => ... } apres.

Les 20 patterns les plus utiles

Logstash inclut des centaines de patterns. Voici ceux que tu utiliseras 90% du temps :

Pattern Matche Exemple
WORD Un mot (lettres, chiffres, underscore) hello, user_42
DATA N'importe quoi (non-greedy) abc 123 !@#
GREEDYDATA N'importe quoi (greedy, va jusqu'a la fin) tout le reste de la ligne
INT Un entier 42, -7
NUMBER Un nombre (entier ou decimal) 3.14, 42
IP Une adresse IPv4 192.168.1.10
IPV6 Une adresse IPv6 ::1
IPORHOST IP ou hostname 192.168.1.10, server01
HOSTNAME Un hostname api.example.com
URI Une URL complète https://example.com/path?q=1
URIPATH Le chemin d'une URL /api/users/42
TIMESTAMP_ISO8601 Date ISO 8601 2026-03-31T14:23:01.456Z
HTTPDATE Date format log HTTP 31/Mar/2026:14:23:01 +0000
LOGLEVEL Niveau de log INFO, ERROR, WARN
EMAILADDRESS Email user@example.com
UUID UUID v4 550e8400-e29b-41d4-a716-446655440000
MAC Adresse MAC 00:1A:2B:3C:4D:5E
PATH Chemin de fichier /var/log/app.log
POSINT Entier positif 200, 42
SPACE Espaces , \t

Et les patterns composes :

Pattern Description
COMBINEDAPACHELOG Ligne de log Apache/Nginx combined
COMMONAPACHELOG Ligne de log Apache common
SYSLOGLINE Ligne syslog complète
SYSLOGBASE En-tête syslog (timestamp + host + process)

Exemple 1 : parser un log Apache combined

Le format Apache combined est le format de log le plus repandu pour les serveurs web :

192.168.1.10 - john [31/Mar/2026:14:23:01 +0000] "GET /api/users HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0"

Le pipeline :

input {
  file {
    path => "/data/apache.log"
    start_position => "beginning"
    sincedb_path => "/dev/null"
  }
}

filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
  }
}

output {
  stdout { codec => rubydebug }
}

Résultat :

json{
  "clientip": "192.168.1.10",
  "ident": "-",
  "auth": "john",
  "timestamp": "31/Mar/2026:14:23:01 +0000",
  "verb": "GET",
  "request": "/api/users",
  "httpversion": "1.1",
  "response": "200",
  "bytes": "1234",
  "referrer": "\"https://example.com\"",
  "agent": "\"Mozilla/5.0\""
}

Un seul pattern, et tu as 11 champs proprement extraits. C'est la puissance de Grok : des annees de regex deja ecrites et testees.

Exemple 2 : parser un log applicatif custom

Tes propres logs n'utilisent pas un format standard. Tu dois écrire le pattern toi-meme. Prenons ce format :

2026-03-31 14:23:01.456 ERROR [api-users] [req-abc123] POST /users 500 5023ms - Connection refused to PostgreSQL

Decomposons :

TIMESTAMP           LEVEL  SERVICE      REQUEST_ID    METHOD URL    STATUS DURATION  MESSAGE
2026-03-31 14:23:01 ERROR  [api-users]  [req-abc123]  POST   /users 500    5023ms    Connection refused...

Le pattern Grok :

filter {
  grok {
    match => {
      "message" => "%{TIMESTAMP_ISO8601:log_timestamp} %{LOGLEVEL:level}\s+\[%{DATA:service}\] \[%{DATA:request_id}\] %{WORD:http_method} %{URIPATH:url} %{INT:status_code:int} %{INT:duration:int}ms - %{GREEDYDATA:error_message}"
    }
  }
}

Construction du pattern, morceau par morceau :

  1. %{TIMESTAMP_ISO8601:log_timestamp} — la date
  2. %{LOGLEVEL:level} — INFO, ERROR, WARN...
  3. \s+ — un ou plusieurs espaces (le LOGLEVEL a une largeur variable)
  4. \[%{DATA:service}\] — le nom du service entre crochets
  5. \[%{DATA:request_id}\] — l'ID de requête entre crochets
  6. %{WORD:http_method} — GET, POST, PUT...
  7. %{URIPATH:url} — le chemin URL
  8. %{INT:status_code:int} — le code HTTP (converti en entier)
  9. %{INT:duration:int}ms — la duree suivie de "ms"
  10. - — le separateur litteral
  11. %{GREEDYDATA:error_message} — tout le reste

GREEDYDATA est toujours en dernier. C'est le "attrape-tout" qui prend le reste de la ligne.

Exemple 3 : parser du syslog

Mar 31 14:23:01 server01 sshd[12345]: Accepted publickey for admin from 10.0.0.5 port 54321 ssh2
filter {
  grok {
    match => { "message" => "%{SYSLOGBASE} %{GREEDYDATA:syslog_message}" }
  }
}

SYSLOGBASE extrait le timestamp, le hostname, le programme et le PID. GREEDYDATA capture le message.

Creer des patterns custom

Quand les patterns built-in ne suffisent pas, tu créés les tiens. Deux méthodes.

Méthode 1 : regex inline

Tu melanges des patterns Grok et de la regex brute dans le meme match :

filter {
  grok {
    match => {
      "message" => "user=%{WORD:username} action=(?<action>[a-z_]+) duration=(?<duration>\d+)ms"
    }
  }
}

La syntaxe (?<field_name>regex) est une capture nommee standard. Ca marche, mais ca devient vite illisible.

Méthode 2 : fichier de patterns

Cree un fichier de patterns dans un dossier dédié :

logstash/
├── pipeline/
│   └── main.conf
└── patterns/
    └── custom

Le fichier custom (pas d'extension) :

# logstash/patterns/custom

APP_TIMESTAMP %{YEAR}-%{MONTHNUM}-%{MONTHDAY} %{HOUR}:%{MINUTE}:%{SECOND}\.%{INT}
APP_LOGLEVEL (TRACE|DEBUG|INFO|WARN|ERROR|FATAL)
SERVICE_NAME [a-zA-Z][a-zA-Z0-9_-]*
REQUEST_ID req-[a-f0-9]+
APP_LOG %{APP_TIMESTAMP:timestamp} %{APP_LOGLEVEL:level}\s+\[%{SERVICE_NAME:service}\] \[%{REQUEST_ID:request_id}\] %{GREEDYDATA:body}

Le format : NOM_PATTERN regex_ou_composition_de_patterns. Un pattern par ligne.

Utilisation dans le pipeline :

filter {
  grok {
    patterns_dir => ["/usr/share/logstash/patterns"]
    match => { "message" => "%{APP_LOG}" }
  }
}

N'oublie pas de monter le dossier dans Docker :

yamllogstash:
  volumes:
    - ./logstash/pipeline/:/usr/share/logstash/pipeline/
    - ./logstash/patterns/:/usr/share/logstash/patterns/:ro

Les patterns custom rendent les pipelines plus lisibles. %{APP_LOG} est plus comprehensible que 200 caractères de regex.

Le Grok Debugger

Écrire un pattern Grok du premier coup, ca n'arrive jamais. Tu as besoin d'un outil pour tester.

Dans Kibana

Ouvre Kibana (http://localhost:5601), va dans "Dev Tools" > "Grok Debugger". Colle ta ligne de log, colle ton pattern, Kibana te montre les champs extraits en temps réel.

En ligne

Le site grokdebugger.com fait la meme chose sans Kibana. Colle ta ligne, colle ton pattern, vois le résultat.

Mon workflow

  1. Je prends 5 lignes de log representatifs (cas normal + erreur + edge cases)
  2. J'ouvre le Grok Debugger dans Kibana
  3. Je construis le pattern morceau par morceau, de gauche a droite
  4. Je teste chaque ligne
  5. Quand ca matche les 5 lignes, je l'intégré dans le pipeline

Plusieurs patterns pour un champ

Parfois, tes logs ont plusieurs formats. Les lignes normales et les lignes d'erreur n'ont pas la meme structure. Grok accepte un tableau de patterns :

filter {
  grok {
    match => {
      "message" => [
        "%{TIMESTAMP_ISO8601:ts} %{LOGLEVEL:level} \[%{DATA:service}\] %{WORD:method} %{URIPATH:url} %{INT:status:int} %{INT:duration:int}ms",
        "%{TIMESTAMP_ISO8601:ts} %{LOGLEVEL:level} \[%{DATA:service}\] %{GREEDYDATA:error_message}"
      ]
    }
    break_on_match => true
  }
}

Avec break_on_match => true (le défaut), Grok essaie les patterns dans l'ordre et s'arrêté au premier qui matche. Le premier pattern est pour les lignes normales (avec method, url, status), le deuxieme est un fallback pour les lignes d'erreur.

Gestion des échecs de parsing

Quand Grok ne matche aucun pattern, il ajoute le tag _grokparsefailure a l'événement. L'événement n'est pas supprime, il continue dans le pipeline avec le tag.

filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
    tag_on_failure => ["_grokparsefailure"]
  }
}

output {
  if "_grokparsefailure" in [tags] {
    file {
      path => "/data/grok-failures.log"
      codec => json_lines
    }
  }

  if "_grokparsefailure" not in [tags] {
    elasticsearch {
      hosts => ["http://elasticsearch:9200"]
      index => "logs-%{+YYYY.MM.dd}"
    }
  }
}

Les événements mal parses vont dans un fichier a part. Tu peux les analyser pour ajuster tes patterns.

En production, surveille le nombre de _grokparsefailure. Si ca monte, c'est qu'un format de log a change ou qu'un nouveau service écrit dans un format que ton pipeline ne connaît pas.

Performance : Grok est lent

Il faut le dire : Grok est le filtre le plus lent de Logstash. Chaque pattern est une regex compilee et exécutée sur le texte. Plus le pattern est complexe, plus c'est lent.

Quelques regles pour limiter les degats :

1. Ancre tes patterns. Si tu sais que la ligne commence par un timestamp, commence le pattern par ^%{TIMESTAMP_ISO8601}. L'ancre ^ évité que le moteur regex essaie de matcher a chaque position.

2. Evite les patterns optionnels longs. (%{GREEDYDATA:extra})? a la fin d'un pattern oblige le moteur a backtracker. Si le champ est parfois absent, utilise deux patterns avec break_on_match.

3. Prefere Dissect quand c'est possible. Si tes logs ont un separateur fixe (espace, pipe, tab), Dissect est 5 a 10 fois plus rapide. On le voit dans l'article suivant.

4. Un Grok, pas cinq. Chaque grok {} dans le pipeline est une passe sur le texte. Extrais tout dans un seul match si possible.

Sur paltemps.fr, je mesure le temps de filtre avec l'API _node/stats. Si un pipeline passe plus de temps en filtre qu'en output, c'est souvent Grok le coupable.

Supprimer le champ message apres parsing

Apres un Grok reussi, le champ message contient encore la ligne brute. Si tu n'en as plus besoin, supprime-le pour economiser de l'espace dans Elasticsearch :

filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
    remove_field => ["message"]
  }
}

Attention : ne supprime message que si ton Grok a bien extrait tous les champs. Sinon tu perds la donnee brute.

Résumé

  • Grok transforme des lignes de texte en champs structures grâce à des patterns nommes
  • %{PATTERN:field} matche et capture, %{PATTERN:field:int} convertit en entier
  • COMBINEDAPACHELOG, SYSLOGLINE et TIMESTAMP_ISO8601 couvrent la majorite des cas
  • Cree des patterns custom dans un fichier dédié pour les formats maison
  • Utilise le Grok Debugger (Kibana ou en ligne) pour tester avant d'intégrer
  • Grok est lent : ancre tes patterns, préféré Dissect pour les formats fixes

Precedent : 08 - Les codecs | Suivant : 10 - Le filtre Dissect

Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.