Logstash pour les devs - 10 - Le filtre Dissect : parser sans regex

Dissect parse les logs structures sans regex. Plus rapide que Grok, plus simple a lire, mais moins flexible.

  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

10 - Le filtre Dissect : parser sans regex

Ce que tu vas apprendre

  • La syntaxe Dissect et comment elle fonctionne sans regex
  • Parser les memes logs qu'avec Grok, mais plus vite
  • Les opérateurs avances : append, padding, key-value
  • Comparer les performances Grok vs Dissect
  • Quand utiliser Dissect et quand rester sur Grok

Prerequisites


Grok m'a rendu paresseux, puis Dissect m'a reveille

Pendant un an, j'ai tout parse avec Grok. Logs applicatifs, Nginx, syslog, CSV. Grok marchait, je ne me posais pas de questions. Jusqu'au jour ou un pipeline a commence a prendre du retard. 50 000 événements par seconde en entree, Logstash n'en traitait que 30 000. Le bottleneck : Grok.

Le pattern faisait 300 caractères. Chaque événement prenait 0.5 ms a parser. Ca parait rien, mais multiplie par 50 000 et tu as 25 secondes de parsing pour 1 seconde de donnees. Le pipeline ne pouvait pas suivre.

J'ai remplace Grok par Dissect sur ce pipeline. Meme résultat, 10 fois plus rapide. Le pipeline a rattrape son retard en 20 minutes.

Comment Dissect fonctionne

Dissect ne fait pas de regex. Il decoupe le texte en se basant sur des delimiteurs fixes. Tu lui dis "il y a un espace ici, un crochet la, un tiret la-bas" et il decoupe.

filter {
  dissect {
    mapping => {
      "message" => "%{timestamp} %{level} [%{service}] %{method} %{url} %{status} %{duration}ms"
    }
  }
}

Ligne d'entree :

2026-03-31 14:23:01 ERROR [api-users] POST /users 500 5023ms

Résultat :

json{
  "timestamp": "2026-03-31 14:23:01",
  "level": "ERROR",
  "service": "api-users",
  "method": "POST",
  "url": "/users",
  "status": "500",
  "duration": "5023"
}

Dissect a trouver les champs en se basant sur les espaces et les crochets. Pas de regex, pas de backtracking, pas de moteur d'expressions regulieres.

La syntaxe

Capture basique

%{field_name}

Capture tout ce qui se trouve entre le delimiteur précédent et le suivant.

Delimiteurs

Les delimiteurs sont le texte litteral entre les %{}. Dans le mapping "%{a} - %{b}", le delimiteur est - (espace tiret espace).

# Espace comme delimiteur
"%{a} %{b} %{c}"

# Pipe comme delimiteur
"%{a}|%{b}|%{c}"

# Crochets
"[%{a}] [%{b}]"

# Texte fixe
"status=%{status} duration=%{duration}"

Ignorer un champ

Si tu veux consommer du texte sans le capturer, utilise ? :

"%{timestamp} %{level} %{?ignore_this} %{message}"

Le troisieme champ est lu et jette. %{?nom} est un champ "poubelle".

Les opérateurs avances

Append : `+`

Concatene plusieurs captures dans le meme champ :

"%{+timestamp} %{+timestamp} %{level} %{message}"

Entree : 2026-03-31 14:23:01 ERROR timeout Résultat : timestamp = "2026-03-31 14:23:01"

Les deux premiers %{+timestamp} sont concatenes avec un espace. L'ordre de concatenation suit l'ordre d'apparition.

Tu peux changer l'ordre avec /N :

"%{+timestamp/2} %{+timestamp/1} %{level} %{message}"

Entree : 14:23:01 2026-03-31 ERROR timeout Résultat : timestamp = "2026-03-31 14:23:01" (l'ordre est inverse grâce à /1 et /2)

Skip padding : `->`

Absorbe les espaces de padding (espaces multiples entre les champs) :

"%{level->} %{message}"

Entree : ERROR Connection timeout (3 espaces entre ERROR et Connection) Résultat : level = "ERROR", message = "Connection timeout"

Sans ->, Dissect s'arrêté au premier espace et level contient ERROR suivi d'espaces.

C'est courant dans les logs ou le niveau est aligne :

INFO    User logged in
WARN    Slow query
ERROR   Connection refused

-> consomme le padding et donne un level propre dans les trois cas.

Key-value : `?` et `&`

Extrait des paires clé-valeur dynamiques :

"%{?key1}=%{&key1} %{?key2}=%{&key2}"

Entree : user=john status=active Résultat : john est stocke dans le champ user, active dans le champ status.

%{?key1} capture le nom du champ (et le jette), %{&key1} capture la valeur et la stocke dans un champ qui porte le nom capture par %{?key1}.

C'est puissant, mais si tes paires clé-valeur sont plus complexes (guillemets, nombre variable), le filtre KV est plus adapte (voir article 13).

Grok vs Dissect : comparaison cote a cote

Prenons la meme ligne de log :

192.168.1.10 - john [31/Mar/2026:14:23:01 +0000] "GET /api/users HTTP/1.1" 200 1234

Avec Grok

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

Avec Dissect

filter {
  dissect {
    mapping => {
      "message" => '%{clientip} %{ident} %{auth} [%{timestamp}] "%{verb} %{request} HTTP/%{httpversion}" %{response} %{bytes}'
    }
  }
}

Le résultat est identique. Les memes champs, les memes valeurs. Mais Dissect est beaucoup plus rapide.

Performance

Metrique Grok Dissect
Temps par événement ~0.5 ms ~0.05 ms
Facteur 1x ~10x plus rapide
CPU Eleve (regex engine) Faible (string split)
Mémoire Compile la regex Aucune compilation

Ces chiffres varient selon la complexité du pattern, mais l'ordre de grandeur est correct : Dissect est 5 a 10 fois plus rapide.

Conversion de types avec convert_datatype

Dissect extrait tout en string. Pour convertir :

filter {
  dissect {
    mapping => {
      "message" => "%{timestamp} %{level} %{service} %{status} %{duration}ms"
    }
    convert_datatype => {
      "status" => "int"
      "duration" => "int"
    }
  }
}

C'est intégré dans Dissect : pas besoin d'un filtre mutate séparé.

Les limites de Dissect

Dissect ne peut pas tout faire. Voici ce qui bloque :

Pas de regex. Si le delimiteur n'est pas fixe, Dissect ne peut pas parser. Un nombre variable d'espaces (sans ->) ou un champ optionnel en fin de ligne font échouer Dissect.

Pas de champs optionnels. Si une ligne peut avoir 5 ou 6 champs, Dissect echoue sur les lignes a 5 champs. Grok gere ca avec (%{GREEDYDATA:extra})?.

Pas de validation. Dissect ne vérifié pas que %{status} est bien un nombre. Il prend tout ce qui est entre les delimiteurs. Un champ corrompu passe sans erreur.

Pas de formats multiples. Grok accepte un tableau de patterns avec break_on_match. Dissect a un seul mapping par filtre.

L'arbre de décision

Le format de tes logs est-il fixe ?
├── Oui (espaces, pipes, crochets, separateurs reguliers)
│   └── Dissect
│       └── + Grok apres si besoin de parser un sous-champ
│
└── Non (formats variables, champs optionnels, regex necessaires)
    └── Grok

En pratique, le pattern le plus courant est de combiner les deux :

filter {
  # Dissect pour le gros du travail (rapide)
  dissect {
    mapping => {
      "message" => "%{timestamp} %{level} [%{service}] %{body}"
    }
  }

  # Grok pour parser un sous-champ complexe (si necessaire)
  if [body] =~ /^(GET|POST|PUT|DELETE)/ {
    grok {
      match => { "body" => "%{WORD:method} %{URIPATH:url} %{INT:status:int} %{INT:duration:int}ms" }
      remove_field => ["body"]
    }
  }
}

Dissect decoupe la structure fixe (timestamp, level, service), et Grok ne parse que le body qui a un format variable. Le moteur regex ne s'exécuté que sur une petite partie de la ligne.

Sur paltemps.fr, c'est la stratégie qu'on utilise sur les pipelines a haut debit : Dissect pour la structure, Grok pour les détails.

Gestion des échecs

Comme Grok, Dissect ajoute un tag en cas d'échec :

filter {
  dissect {
    mapping => {
      "message" => "%{ts} %{level} %{msg}"
    }
    tag_on_failure => ["_dissectfailure"]
  }
}

Le tag par défaut est _dissectfailure. Surveille-le comme tu surveillerais _grokparsefailure.

Résumé

  • Dissect parse sans regex, en se basant sur des delimiteurs fixes
  • 5 a 10 fois plus rapide que Grok sur les memes donnees
  • Operateurs : + (append), -> (skip padding), ?/& (key-value)
  • convert_datatype évité un mutate séparée
  • Ne gere pas les champs optionnels ni les formats multiples
  • Combine Dissect (structure) + Grok (détails) pour le meilleur des deux mondes

Precedent : 09 - Le filtre Grok | Suivant : 11 - Le filtre Mutate

Sources

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