Logstash pour les devs - 23 - Dead Letter Queue : ne plus perdre d'événements

Configurer et exploiter la dead letter queue pour récupérer les événements rejetes par Elasticsearch.

  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

23 - Dead Letter Queue : ne plus perdre d'événements

Ce que tu vas apprendre

  • Ce qu'est la Dead Letter Queue (DLQ) et quand elle se remplit
  • Activer et configurer la DLQ
  • Lire les événements de la DLQ avec un pipeline de reprocessing
  • Les stratégies pour corriger et re-indexer les événements rejetes
  • Surveiller la taille de la DLQ

Prerequisites

  • Connaitre l'output Elasticsearch (voir article 17)
  • Connaitre les pipelines multiples (voir article 20)

Le problème : Elasticsearch rejette des documents

Tu as un pipeline qui tourne depuis des semaines. Un jour, un développeur change le format d'un champ dans les logs : status_code passe de "200" (string) a 200 (integer). Ton mapping Elasticsearch attend un keyword. Le document est rejete avec un mapper_parsing_exception.

Sans la DLQ, cet événement est perdu. Logstash log l'erreur et passe au suivant. Avec la DLQ, l'événement est sauvegarde sur disque. Tu peux le corriger et le re-indexer plus tard.

Ce qui déclenché la DLQ

La DLQ recoit les événements que l'output Elasticsearch n'a pas pu indexer apres toutes les retries. Les causes les plus courantes :

Erreur Cause Exemple
mapper_parsing_exception Type de champ incorrect String dans un champ integer
illegal_argument_exception Valeur invalide Date mal formee
version_conflict_engine_exception Conflit de version Deux updates simultanes du meme doc
document_parsing_exception JSON invalide Champ avec des caractères de contrôle

Les erreurs 429 (Too Many Requests) et 503 (Service Unavailable) ne vont PAS dans la DLQ. Logstash les retente automatiquement (voir article 17).

Activer la DLQ

Dans logstash.yml

yaml# logstash/config/logstash.yml

dead_letter_queue.enable: true
dead_letter_queue.max_bytes: 1024mb
dead_letter_queue.storage_policy: drop_newer
dead_letter_queue.flush_interval: 5000
Paramètre Description
dead_letter_queue.enable Active la DLQ (défaut: false)
dead_letter_queue.max_bytes Taille max sur disque (défaut: 1024 Mo)
dead_letter_queue.storage_policy Que faire quand la DLQ est pleine : drop_newer (défaut) ou drop_older
dead_letter_queue.flush_interval Frequence d'écriture sur disque en ms

Ou sont stockes les fichiers DLQ

/usr/share/logstash/data/dead_letter_queue/
└── main/                    # nom du pipeline
    ├── 1.log                # premier segment
    ├── 2.log                # deuxieme segment
    └── .lock                # verrou

Monte un volume Docker pour persister la DLQ entre les redemarrages :

yamllogstash:
  volumes:
    - logstash-data:/usr/share/logstash/data

Le pipeline de reprocessing

Pour relire les événements de la DLQ, créé un pipeline dédié avec l'input dead_letter_queue :

# logstash/pipeline/dlq-reprocess.conf

input {
  dead_letter_queue {
    path => "/usr/share/logstash/data/dead_letter_queue"
    pipeline_id => "main"
    commit_offsets => true
  }
}

filter {
  # L'evenement original est dans les champs normaux
  # Les metadonnees DLQ sont dans [@metadata]

  # Voir la raison du rejet
  ruby {
    code => '
      reason = event.get("[@metadata][dead_letter_queue][reason]")
      plugin = event.get("[@metadata][dead_letter_queue][plugin_type]")
      event.set("dlq_reason", reason)
      event.set("dlq_plugin", plugin)
    '
  }

  # Corriger le probleme selon le type d'erreur
  if [dlq_reason] =~ /mapper_parsing_exception/ {
    # Forcer la conversion des champs problematiques
    mutate {
      convert => {
        "status_code" => "string"
        "duration" => "string"
      }
    }
  }

  # Nettoyer les champs DLQ avant re-indexation
  mutate {
    remove_field => ["dlq_reason", "dlq_plugin"]
  }
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "logs-recovered-%{+YYYY.MM.dd}"
  }
}

Metadonnees DLQ

Chaque événement DLQ contient des metadonnees sur le rejet :

json{
  "@metadata": {
    "dead_letter_queue": {
      "plugin_id": "elasticsearch_1",
      "plugin_type": "elasticsearch",
      "reason": "mapper_parsing_exception: failed to parse field [status_code] of type [keyword] in document...",
      "entry_time": "2026-03-31T14:23:01.000Z"
    }
  }
}
  • plugin_id : quel output a rejete l'événement
  • reason : le message d'erreur complet d'Elasticsearch
  • entry_time : quand l'événement a ete mis en DLQ

pipelines.yml avec le pipeline DLQ

yaml- pipeline.id: main
  path.config: "/usr/share/logstash/pipeline/main.conf"
  pipeline.workers: 4

- pipeline.id: dlq-reprocess
  path.config: "/usr/share/logstash/pipeline/dlq-reprocess.conf"
  pipeline.workers: 1
  pipeline.batch.size: 50

Le pipeline DLQ tourne en parallèle du pipeline principal. Il lit les événements rejetes, les corrige et les re-indexé dans un index séparé (logs-recovered-*).

Stratégies de correction

1. Convertir les types

La cause la plus frequente. Un champ a change de type dans les logs source.

filter {
  mutate {
    convert => {
      "status_code" => "string"
    }
  }
}

2. Supprimer les champs problématiques

Si un champ est corrompu et que tu n'en as pas besoin :

filter {
  mutate {
    remove_field => ["corrupted_field"]
  }
}

3. Re-indexer dans un index différent

Si le mapping de l'index original ne peut pas etre change (il est deja utilise par d'autres documents) :

output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "logs-recovered-%{+YYYY.MM.dd}"
  }
}

L'index logs-recovered-* a son propre mapping qui accepte les types corriges.

4. Envoyer les événements non recuperables dans un fichier

Si certains événements ne peuvent pas etre corriges :

output {
  if [dlq_unrecoverable] == "true" {
    file {
      path => "/data/dlq-unrecoverable-%{+YYYY-MM-dd}.json"
      codec => json_lines
    }
  } else {
    elasticsearch {
      hosts => ["http://elasticsearch:9200"]
      index => "logs-recovered-%{+YYYY.MM.dd}"
    }
  }
}

Surveiller la DLQ

Verifie régulièrement la taille de la DLQ :

bash# Taille des fichiers DLQ
docker exec logstash du -sh /usr/share/logstash/data/dead_letter_queue/

Si la DLQ grossit, c'est qu'un problème recurrent envoie des événements en erreur. Corrige la cause racine (mapping, format de log, pipeline) plutot que de juste reprocesser.

Sur paltemps.fr, on a une alerte quand la DLQ dépassé 100 Mo. Ca veut dire que plus de ~100 000 événements ont ete rejetes. A chaque fois, la cause etait un changement de format dans les logs d'une application sans mise à jour du pipeline.

Résumé

  • La DLQ sauvegarde les événements rejetes par Elasticsearch sur disque
  • Activee avec dead_letter_queue.enable: true dans logstash.yml
  • Un pipeline dédié lit la DLQ, corrige les événements et les re-indexé
  • Les causes les plus courantes : mapping conflicts, types incorrects, valeurs invalides
  • Les erreurs 429/503 ne vont pas en DLQ (Logstash les retente automatiquement)
  • Surveille la taille de la DLQ et corrige la cause racine

Precedent : 22 - Monitoring | Suivant : 24 - Sécurité

Sources

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