Comment créer des pipelines Logstash maintenables et réutilisables
Logstash est un pipeline open source destiné au traitement des données. Sa mission ? Ingérer des événements depuis une ou plusieurs entrées, les transformer, puis envoyer chacun d'eux vers une ou plusieurs sorties. Certaines implémentations Logstash peuvent avoir plusieurs lignes de code et peuvent traiter les événements depuis différentes sources d'entrée. Afin de faciliter la gestion de telles implémentations, je vais vous montrer comment créer des pipelines à partir de composants modulaires, ce qui rend le code plus facilement réutilisable.
Motivation
Logstash doit souvent appliquer un sous-ensemble logique commun à des événements provenant de différentes sources d'entrée. Pour ce faire, on adopte généralement l'une de ces deux approches :
- Traiter les événements provenant de différentes sources d'entrée dans un seul pipeline, afin de faciliter l'application d'une logique commune à tous les événements, quelle que soit leur source. Dans de telles implémentations, outre la logique commune, on trouve aussi habituellement un nombre considérable de logiques conditionnelles. Par conséquent, cette approche peut se traduire par des implémentations Logstash complexes et difficiles à comprendre.
- Exécuter un pipeline unique pour le traitement des événements provenant de chaque source d'entrée unique. Cette approche nécessite de dupliquer et de copier dans chaque pipeline une fonctionnalité commune, ce qui complique la gestion des parties de code communes.
La méthode présentée dans cet article de blog répond aux inconvénients des deux approches ci-dessus : elle permet de stocker des composants de pipeline modulaires dans différents fichiers, puis d'associer ces composants pour créer des pipelines. Cette méthode peut vous permettre de simplifier le pipeline et vous éviter la duplication de code.
Création d'un pipeline modulaire
Un fichier de configuration Logstash est composé d'entrées, de filtres et de sorties, qui sont exécutés par un pipeline Logstash. Dans les configurations avancées, on trouve assez souvent une instance Logstash exécutant plusieurs pipelines. Par défaut, lorsque vous lancez Logstash sans argument, il lit un fichier nommé pipelines.yml
et instancie les pipelines spécifiés.
Vous pouvez stocker les entrées, les filtres et les sorties Logstash dans différents fichiers, que vous pouvez choisir d'inclure dans un pipeline en spécifiant une expression glob. Les fichiers qui correspondent à une expression glob sont alors associés dans l'ordre alphabétique. L'ordre d'exécution des filtres étant souvent important, il peut être utile d'inclure des identifiants numériques dans les noms des fichiers, afin qu'ils soient associés dans l'ordre voulu.
Ci-dessous, nous allons définir deux pipelines uniques, qui sont en fait l'association de plusieurs composants Logstash modulaires. Nous allons stocker nos composants Logstash components dans les fichiers suivants :
- Déclarations d'entrée :
01_in.cfg
,02_in.cfg
- Déclarations de filtre :
01_filter.cfg
,02_filter.cfg
,03_filter.cfg
- Déclarations de sortie :
01_out.cfg
Au moyen d'expressions glob, nous allons ensuite définir les pipelines dans pipelines.yml
, pour qu'ils comprennent les composants voulus, comme suit :
- pipeline.id: my-pipeline_1 path.config: "<path>/{01_in,01_filter,02_filter,01_out}.cfg" - pipeline.id: my-pipeline_2 path.config: "<path>/{02_in,02_filter,03_filter,01_out}.cfg"
Dans la configuration de pipelines ci-dessus, le fichier 02_filter.cfg
est présent dans les deux pipelines. On voit donc que le code commun aux deux pipelines peut être défini et géré dans un seul fichier, tout en s'exécutant sur plusieurs pipelines.
Tester les pipelines
Dans cette partie, nous allons prendre un exemple concret pour illustrer les fichiers qui seront associés dans les pipelines uniques que nous avons définis ci-dessus dans pipelines.yml
. Nous lancerons ensuite Logstash avec ces fichiers et verrons le résultat ainsi généré.
Fichiers de configuration
Fichier d'entrée : 01_in.cfg
L'entrée que définit ce fichier est un générateur. L'entrée générateur sert à tester Logstash et dans cet exemple, elle va générer un seul événement.
input { generator { lines => ["Generated line"] count => 1 } }
Fichier d'entrée : 02_in.cfg
Ce fichier définit une entrée Logstash qui écoute sur stdin .
input { stdin {} }
Fichier de filtre : 01_filter.cfg
filter { mutate { add_field => { "filter_name" => "Filter 01" } } }
Fichier de filtre : 02_filter.cfg
filter { mutate { add_field => { "filter_name" => "Filter 02" } } }
Fichier de filtre : 03_filter.cfg
filter { mutate { add_field => { "filter_name" => "Filter 03" } } }
Fichier de sortie : 01_out.cfg
output { stdout { codec => "rubydebug" } }
Exécuter le pipeline
Lorsqu'on démarre Logstash sans définir aucune option, on exécute le fichier pipelines.yml
défini précédemment. Exécuter Logstash comme suit :
./bin/logstash
Comme le pipeline my-pipeline_1
exécute un générateur pour simuler un événement d'entrée, nous devons voir le résultat suivant aussitôt l'initialisation de Logstash terminée. Nous voyons que ce pipeline exécute les contenus de 01_filter.cfg
et 02_filter.cfg
comme prévu.
{ "sequence" => 0, "host" => "alexandersmbp2.lan", "message" => "Generated line", "@timestamp" => 2020-02-05T22:10:09.495Z, "@version" => "1", "filter_name" => [ [0] "Filter 01", [1] "Filter 02" ] }
Étant donné que l'autre pipeline nommé my-pipeline_2
attend une entrée sur stdin, nous voyons qu'il n'a encore traité aucun événement. Saisissez quelque chose dans le terminal sur lequel s'exécute Logstash et appuyez sur la touche Retour pour créer un événement pour ce pipeline. Une fois cela fait, le résultat qui s'affiche doit ressembler à ceci :
{ "filter_name" => [ [0] "Filter 02", [1] "Filter 03" ], "host" => "alexandersmbp2.lan", "message" => "I’m testing my-pipeline_2", "@timestamp" => 2020-02-05T22:20:43.250Z, "@version" => "1" }
Nous voyons ci-dessus que la logique provenant de 02_filter.cfg
et03_filter.cfg
est appliquée comme prévu.
Ordre d'exécution
Il faut savoir que Logstash ne tient pas compte de l'ordre des fichiers de l'expression glob. Il n'utilise l'expression glob que pour identifier les fichiers à inclure, puis les classe dans l'ordre alphabétique. Autrement dit, même si nous modifions la définition de my-pipeline_2
pour que 03_filter.cfg
apparaisse avant 02_filter.cfg
dans l'expression glob, les événements passeront d'abord par le filtre défini dans 02_filter.cfg
avant de passer par celui de 03_filter.cfg
.
Pour conclure
L'utilisation d'expressions glob permet de créer des pipelines Logstash à partir de composants modulaires stockés en tant que fichiers distincts. Cela peut faciliter la gestion, la réutilisation et la lisibilité du code.
Par ailleurs, je vous invite à consulter la page pipeline-to-pipeline communication (communication de pipeline à pipeline), qui peut aussi vous aider à améliorer la modularité de votre implémentation Logstash.