Béjean Développement

Créer un conteneur Docker pour traiter vos logs Magento 2 avec Logstash

Objectif

Faire remonter l'ensemble des logs Magento 2 vers un ELK en utilisant Logstash.

Pré-requis

Dans cet article, nous verrons uniquement la mise en place d'un container Logstash sous Docker pour envoyer vos logs à un serveur Elasticsearch.

Si vous souhaitez mettre en place un serveur ELK, je vous invite à prendre connaissance de la playlist ELK de Xavki, lien vers la playlist.

Tutoriel

Création du projet

Arborescence

Commençons par créer un dossier dans lequel nous allons travailler :

mkdir m2-logstash && cd m2-logstash

Dans ce dossier, nous allons créer les dossiers pour les volumes persistants de notre conteneur Docker :

mkdir -p conf/logstash

Fichier de configuration : logstash.yml

Dans le dossier conf/logstash, nous allons créer le fichier logstash.yml qui contiendra :

http.host: "0.0.0.0"
xpack.monitoring.enabled: false
xpack.monitoring.elasticsearch.hosts: [ "http://url-elasticsearch:9200" ]

Avant d'enregistrer et de fermer le fichier, n'oubliez pas de modifier url-elasticsearch vers l'URL de votre serveur Elasticsearch.

Si vous souhaitez plus d'informations sur la configuration, je vous invite à consulter la documentation, lien vers la documentation.

Pour éviter les erreurs dans les logs de Logstash, j'ai ajouté les 2 lignes concernant xpack.

Fichier : logstash.Dockerfile

Pour lancer le conteneur de Logstash, nous avons besoin de 2 lignes pour le moment.

FROM logstash:7.9.3

COPY ./conf/logstash/logstash.yml /usr/share/logstash/config/logstash.yml

Veillez bien à utiliser la version de Logstash compatible avec votre serveur Elasticsearch.

Fichier : docker-compose.yml

A la racine de notre projet (dossier m2-logstash), nous allons créer un fichier docker-compose.yml contenant :

version: '3'
services:
  logstash:
    build:
      context: .
      dockerfile: logstash.Dockerfile
    networks:
      - myNetwork

networks:
  myNetwork:
    driver: bridge

Configuration de Logstash

Magento 2 génère ses logs dans le dossier var/log, nous allons donc configurer Logstash pour qu'il consulte en permanence ce dossier.

Pour cela, il faut que les logs de Magento soit accessible par la machine hôte. Dans mon cas, je lance Magento 2 avec Docker, lien vers le tutoriel.

Mise en place du volume persistant

Une fois que les fichiers de logs sont accessibles sur la machine hôte, il faut mettre en place un volume persistant à notre conteneur logstash avec les 2 lignes ci-dessous :

volumes:
  - ./racine_de_magento/var/log:/var/log/magento

Les 2 lignes sont à ajouter au fichier docker-compose.yml, le résultat est le suivant :

version: '3'
services:
  logstash:
    build:
      context: .
      dockerfile: logstash.Dockerfile
    volumes:
      - ./racine_de_magento/var/log:/var/log/magento
    networks:
      - myNetwork

networks:
  myNetwork:
    driver: bridge

N'oubliez pas de remplacer racine_de_magento.

Fichier de traitement des logs

Concentrons-nous maintenant sur le fichier de configuration pour le traitement des logs Magento 2.

Le fichier ci-dessous est composé de 3 parties :

  • input
  • filter
  • output

Vous retrouverez quelques explications sur chaque paramètre utilisé à la fin du tutoriel.

Le contenu ci-dessous doit être insérer dans un fichier nommé magento2.conf dans le dossier conf/logstash.

input {
  file {
    type => "magento-log"
    path => "/var/log/magento/*.log"
    exclude => ["*.gz"]
    codec => multiline {
      pattern => "^\[%{TIMESTAMP_ISO8601}\]"
      negate => true
      what => "previous"
    }
  }
}

filter {
  if [type] == "magento-log" {

    grok {
      match => {
        "message"  => "\[%{TIMESTAMP_ISO8601:date}\] %{WORD:word}.%{WORD:level}: %{GREEDYDATA:content} \[\]"
      }
    }

    date {
      match => ["date", "yyyy-MM-dd HH:mm:ss"]
      timezone => "Europe/Paris"
    }

    mutate {
      copy => { "[@timestamp]" => "date" }
      add_tag => [ "%{level}" ]
    }

    if "_grokparsefailure" in [tags] {
      mutate {
        remove_field => [ "message" ]
      }
    }
  }
}

output {
  if [type] == "magento-log" {
    elasticsearch {
      hosts => ["url-elasticsearch:9200"]
      index => "magento2-%{+YYYY.MM.dd}"
    }

    if "_grokparsefailure" in [tags] {
      elasticsearch {
        hosts => ["url-elasticsearch:9200"]
        index => "magento2_grokparsefailure-%{+YYYY.MM.dd}"
      }
    }
  }
}

Avant d'enregistrer et de fermer le fichier, n'oubliez pas de modifier url-elasticsearch vers l'URL de votre serveur Elasticsearch.

Une fois le fichier enregistré, nous allons copier ce ficiher dans le conteneur en modifiant le fichier logstatsh.Dockerfile. Ajouter à la fin du fichier la directive :

COPY ./conf/logstash/magento2.conf /usr/share/logstash/pipeline/magento2.conf

Enregister et fermer le fichier. Puis lancer la commande :

docker-compose build && docker-compose up -d

Résultat

Pour contrôler que les données remontent correctement, je vous invite à activer les crons de votre boutique en ligne puis de lancer la commande docker logs m2-logstash_logstash_1 -f où de d'ouvrir Kibana dans votre navigateur.

Dans mon cas, le conteneur Logstash est : m2-logstash_logstash_1.

Tutoriel publié le 23/11/2020.

Les paramètres utilisés

Bloc : Input

Pour traiter les fichiers, nous utilisons le plugin file de Logstash, lien vers la documentation.

Voici un résumé des propriétés que j'ai utilisées pour la partie :

  • type : Ce paramètre sera présent dans Elasticsearch et nous servira pour poser quelques conditions dans le fichier de configuration.
  • path : Indique à Logstash le ou les fichiers à traiter
  • exclude : Exclude est un tableau qui permet d'exclure le traitement de certains fichiers, dans mon cas, je refuse de traiter les fichiers *.gz
  • codec : Permet de traiter plusieurs lignes de logs en se basant sur un pattern, lien vers la documentation

Bloc : Filter

Le bloc filter permet de traiter le contenu de chaque fichier. J'ai ajouté la condition if [type] == "magento-log" {} pour sécuriser le traitement des logs par Logstash. On peut également personnaliser le traitement des logs.

Le découpage des lignes de chaque fichier est traité par le plugin grok, lien vers la documentation. C'est un plugin assez puissant basé sur les expressions régulières. Dans le cas où grok ne parviendrait pas à parser les logs, il ajoute le tag _grokparsefailure.

Le plugin date permet de faire correspondre le format de date du fichier pour un traitement. Dans notre cas, je fais correspondre la date des fichiers de log Magento 2 pour le copier dans le champ [@timestamp]. Ceci est très important car lors de l'analyse des logs, il n'y aura pas d'erreur de date et d'heure, lien vers la documentation. J'en profite également pour renseigner le fuseau horaire.

Le plugin mutate me sert pour remplacer le contenu du champ date dans le champ [@timestamp] et aussi pour ajouter le tag level qui correspond au niveau de gravité du log, lien vers la documentation.

Nous finissons par la condition if "_grokparsefailure" in [tags] {} qui va supprimer le champ message lorsque le plugin grok n'aura pas rencontré d'erreur. Ceci permet également de réduire le volume de données stockés par le serveur Elasticsearch.

Bloc : Output

Comme pour le bloc filter, j'ai ajouté une condition autour des 2 paramètres dans le but de sécuriser l'envoi des données sur le serveur Elasticsearch. Il existe plusieurs plugins de sortie pour Logstash, voir la liste. Dans mon cas, j'ai utilisé le plugin Elasticsearch, lien vers la documentation.

Très simplement, nous envoyons les données au serveur Elasticsearch de notre choix en précisant le nom de l'index magento2-%{+YYYY.MM.dd}. L'index est horodaté pour éviter un poids important.

Nous utilisons à nouveau la condition if "_grokparsefailure" in [tags] {} pour également envoyer, dans un autre index, les erreurs rencontrées par grok lors du traitement des journaux.