Logstash pour les devs - 26 - Tester ses pipelines avant la prod

Tester un pipeline Logstash avec des donnees de test, des assertions et de la CI. Valider avant de déployer.

  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

26 - Tester ses pipelines avant la prod

Ce que tu vas apprendre

  • Valider la syntaxe d'un pipeline sans le démarrer
  • Tester un pipeline avec des donnees d'echantillon
  • Écrire un script de test automatise
  • Intégrer la validation dans une CI (GitHub Actions)
  • Organiser les fichiers de test

Prerequisites

  • Avoir un pipeline a tester
  • Connaitre Docker et Docker Compose

Tester un pipeline, c'est pas optionnel

J'ai pousse un changement de pipeline Logstash en prod un vendredi soir. Un caractère en trop dans un pattern Grok. Le pipeline a recharge a chaud, le Grok a echoue sur 100% des événements, et tous les logs de la nuit sont partis dans _grokparsefailure sans les champs extraits. Les dashboards Kibana etaient vides le lundi matin.

Depuis, je teste chaque changement de pipeline avant de déployer. Pas avec des outils sophistiques. Avec des fichiers de test et un script bash.

Validation de syntaxe

La première vérification, la plus rapide :

bashdocker exec logstash bin/logstash --config.test_and_exit \
  -f /usr/share/logstash/pipeline/main.conf

Si la syntaxe est valide :

Configuration OK

Si elle est invalide :

ERROR: Expected one of [ \t\r\n], "#", "input", "filter", "output" at line 14, column 3

Le message indique la ligne et la colonne. Ca détecté les accolades manquantes, les => oublies, et les blocs mal fermes.

Dans un script

bash#!/bin/bash
# scripts/validate.sh

CONFIG_DIR="/usr/share/logstash/pipeline"
ERRORS=0

for conf in ${CONFIG_DIR}/*.conf; do
  echo "Validating $(basename $conf)..."
  if docker exec logstash bin/logstash --config.test_and_exit -f "$conf" 2>&1 | grep -q "Configuration OK"; then
    echo "  OK"
  else
    echo "  FAILED"
    ERRORS=$((ERRORS + 1))
  fi
done

if [ $ERRORS -gt 0 ]; then
  echo "FAILED: $ERRORS file(s) with errors"
  exit 1
fi

echo "All configurations valid"

Tester avec des donnees d'echantillon

La validation de syntaxe ne détecté pas les erreurs logiques. Un pattern Grok valide peut ne rien matcher. Pour ca, tu as besoin de donnees de test.

Structure du projet de test

logstash/
├── pipeline/
│   └── main.conf
├── test/
│   ├── input/
│   │   ├── nginx-access.log
│   │   ├── app-json.log
│   │   └── edge-cases.log
│   ├── expected/
│   │   ├── nginx-expected.json
│   │   └── app-expected.json
│   └── pipeline/
│       └── test-main.conf
└── scripts/
    └── test.sh

Fichiers de test

# test/input/nginx-access.log

192.168.1.10 - admin [31/Mar/2026:14:23:01 +0000] "GET /api/users HTTP/1.1" 200 1234 "https://example.com" "Mozilla/5.0"
10.0.0.5 - - [31/Mar/2026:14:23:02 +0000] "POST /api/orders HTTP/1.1" 201 567 "-" "curl/8.4.0"
invalid line that should fail grok
192.168.1.10 - admin [31/Mar/2026:14:23:03 +0000] "DELETE /api/users/42 HTTP/1.1" 404 89 "-" "Mozilla/5.0"

La troisieme ligne est intentionnellement invalide. On veut vérifier que le pipeline gere le cas d'erreur.

Pipeline de test

Le pipeline de test remplace les inputs/outputs par des versions locales :

# test/pipeline/test-main.conf

input {
  file {
    path => "/test/input/nginx-access.log"
    start_position => "beginning"
    sincedb_path => "/dev/null"
    exit_after_read => true
  }
}

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

  date {
    match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
    target => "@timestamp"
    remove_field => ["timestamp"]
  }

  mutate {
    convert => {
      "response" => "integer"
      "bytes" => "integer"
    }
    remove_field => ["message", "@version", "event", "host", "log"]
  }
}

output {
  file {
    path => "/test/output/result.json"
    codec => json_lines
  }
}

Le exit_after_read => true (disponible dans les versions recentes du file input) fait que Logstash quitte apres avoir lu tout le fichier. Pas besoin de timeout.

Le script de test

bash#!/bin/bash
# scripts/test.sh

set -e

echo "=== Logstash Pipeline Tests ==="

# Nettoyer les outputs precedents
rm -f test/output/result.json

# Lancer Logstash avec le pipeline de test
echo "Running pipeline on test data..."
docker run --rm \
  -v "$(pwd)/test:/test" \
  -v "$(pwd)/logstash/patterns:/usr/share/logstash/patterns:ro" \
  docker.elastic.co/logstash/logstash:8.17.0 \
  bin/logstash -f /test/pipeline/test-main.conf \
  --path.data /tmp/logstash-test \
  2>/dev/null

# Verifier que l'output existe
if [ ! -f test/output/result.json ]; then
  echo "FAIL: No output produced"
  exit 1
fi

# Compter les evenements
TOTAL=$(wc -l < test/output/result.json)
echo "Events produced: $TOTAL"

# Verifier le nombre d'evenements attendus
EXPECTED=3
if [ "$TOTAL" -ne "$EXPECTED" ]; then
  echo "FAIL: Expected $EXPECTED events, got $TOTAL"
  exit 1
fi

# Verifier qu'un evenement a le tag _grokparsefailure (la ligne invalide)
FAILURES=$(grep -c "grokparsefailure" test/output/result.json || true)
if [ "$FAILURES" -ne 1 ]; then
  echo "FAIL: Expected 1 grok failure, got $FAILURES"
  exit 1
fi

# Verifier les champs d'un evenement valide
FIRST=$(head -1 test/output/result.json)
if echo "$FIRST" | python3 -c "
import json, sys
e = json.load(sys.stdin)
assert e['response'] == 200, f'Expected 200, got {e[\"response\"]}'
assert e['verb'] == 'GET', f'Expected GET, got {e[\"verb\"]}'
assert e['clientip'] == '192.168.1.10', f'Expected 192.168.1.10, got {e[\"clientip\"]}'
print('Field assertions: OK')
" 2>&1; then
  echo "Field checks: PASSED"
else
  echo "FAIL: Field assertions failed"
  exit 1
fi

echo ""
echo "=== All tests PASSED ==="

Ce script :

  1. Lance Logstash dans un conteneur éphémère avec le pipeline de test
  2. Verifie que le bon nombre d'événements est produit
  3. Verifie qu'un événement a echoue au Grok (la ligne invalide)
  4. Verifie les champs d'un événement valide (type, valeur)

Intégration CI : GitHub Actions

yaml# .github/workflows/logstash-test.yml

name: Test Logstash Pipelines

on:
  push:
    paths:
      - 'logstash/**'
  pull_request:
    paths:
      - 'logstash/**'

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Validate pipeline syntax
        run: |
          for conf in logstash/pipeline/*.conf; do
            echo "Validating $conf..."
            docker run --rm \
              -v "$(pwd)/logstash/pipeline:/pipeline:ro" \
              docker.elastic.co/logstash/logstash:8.17.0 \
              bin/logstash --config.test_and_exit \
              -f "/pipeline/$(basename $conf)"
          done

      - name: Run pipeline tests
        run: |
          chmod +x scripts/test.sh
          ./scripts/test.sh

La CI :

  1. Se déclenché quand un fichier dans logstash/ change
  2. Valide la syntaxe de chaque .conf
  3. Execute le script de test avec des donnees d'echantillon

Si un test echoue, le PR est bloque. Plus de pipeline casse en prod.

Bonnes pratiques

Fichiers de test representatifs

Inclus dans tes fichiers de test :

  • Des lignes normales (le cas standard)
  • Des lignes avec des champs manquants
  • Des lignes avec des caractères speciaux (accents, emojis, unicode)
  • Des lignes volontairement invalides (pour tester la gestion d'erreur)
  • Les edge cases de ta production (les formats rares que tu as deja rencontres)

Versionner les fichiers de test

Les fichiers de test sont dans le meme repo que les pipelines. Quand tu modifies un pattern Grok, tu mets à jour les fichiers de test dans le meme commit.

Un test par pipeline

Si tu as 3 pipelines (nginx, app, syslog), tu as 3 jeux de test avec 3 scripts. Pas un mega-test qui teste tout.

Sur paltemps.fr, chaque modification de pipeline passe par un PR avec les tests qui tournent en CI. Ca prend 30 secondes. Ca évité les catastrophes du vendredi soir.

Résumé

  • --config.test_and_exit valide la syntaxe sans démarrer le pipeline
  • Teste avec des fichiers d'echantillon representatifs (cas normaux + erreurs + edge cases)
  • Le script de test lance Logstash dans un conteneur éphémère et vérifié les outputs
  • La CI valide automatiquement chaque changement de pipeline
  • Inclus des lignes invalides dans les tests pour vérifier la gestion d'erreur
  • Un jeu de test par pipeline, versionne avec le code

Precedent : 25 - Debugging | Suivant : 27 - Cas pratique : logs applicatifs

Sources

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