Fluentd Fluentd

Collecter des logs depuis des fichiers, HTTP et des conteneurs

Configurez les trois sources d'entrée les plus courantes : un fichier sur disque, un endpoint HTTP et tous les conteneurs d'un hôte Docker.

12 min Intermédiaire

La plupart des déploiements réels ont besoin de plusieurs types de sources d’entrée à la fois : une application existante qui écrit dans un fichier de log, un service qui peut plutôt pousser ses logs en HTTP, et tous les conteneurs qui tournent sur un hôte. Ce guide configure les trois, en s’appuyant sur la structure source/filter/match présentée dans le guide précédent.

Suivre un fichier de log

Le plugin d’entrée tail suit un fichier comme le fait tail -f, en récupérant les nouvelles lignes au fur et à mesure qu’elles sont écrites :

<source>
  @type tail
  path /var/log/apache2/access.log
  pos_file /var/log/fluent/apache-access.log.pos
  tag apache.access
  <parse>
    @type apache2
  </parse>
</source>

pos_file mérite d’être pris au sérieux même s’il est facile de l’omettre : c’est là que Fluentd enregistre exactement jusqu’où il a déjà lu le fichier. Sans lui, redémarrer Fluentd signifie relire tout le fichier depuis le début, en dupliquant tout ce qui a déjà été expédié. Avec lui, un redémarrage reprend exactement là où il s’était arrêté. La documentation du plugin le décrit comme fortement recommandé pour cette raison précise.

Accepter des logs en HTTP

On ne peut pas toujours installer Fluentd à côté de tout. Un service cloud managé, une fonction serverless, tout ce qui se trouve hors de l’infrastructure que vous contrôlez au niveau du système d’exploitation, ne peut pas faire tourner une source tail à côté d’un fichier qu’il écrit. Pour ces cas, le plugin d’entrée http permet à quelque chose d’envoyer des logs vers Fluentd au lieu que Fluentd les lise depuis lui :

<source>
  @type http
  port 9880
  bind 0.0.0.0
  body_size_limit 32m
  keepalive_timeout 10s
</source>

Tout ce qui peut émettre une requête HTTP POST (une application personnalisée, une bibliothèque de logging configurée pour y transférer, un appel curl dans un script) peut désormais livrer directement des données de log. Il vaut mieux définir délibérément body_size_limit et keepalive_timeout plutôt que de laisser la valeur par défaut de votre version, car une source HTTP est exposée à tout le trafic qui l’atteint, et des tailles de requête illimitées ou des connexions maintenues ouvertes sont le genre de choses que l’on veut maîtriser soi-même plutôt que de s’en remettre au comportement par défaut.

Collecter les logs de tous les conteneurs d’un hôte

Docker (et les runtimes de conteneurs en général) écrit la sortie stdout/stderr de chaque conteneur dans des fichiers de log au format JSON sur l’hôte, un répertoire par conteneur. Pointer une source tail vers tous ces fichiers avec un joker suffit à collecter la sortie de chaque conteneur sans configurer chacun individuellement :

<source>
  @type tail
  path /fluentd/log/containers/*/*-json.log
  pos_file /var/log/fluent/docker.log.pos
  tag docker.*
  read_from_head true
  <parse>
    @type json
  </parse>
</source>

Pour que cela fonctionne, le répertoire de logs Docker de l’hôte (/var/lib/docker/containers par défaut) doit effectivement être monté là où Fluentd s’exécute, au chemin vers lequel pointe le motif path de la source. C’est précisément ainsi que Fluentd fonctionne aussi en DaemonSet Kubernetes : un Pod Fluentd par nœud, chacun montant le répertoire de logs de conteneurs de son propre nœud, de sorte que sur tout un cluster, les conteneurs de chaque nœud sont collectés de la même façon sans configuration par conteneur.

read_from_head true indique à Fluentd de commencer au début des fichiers qu’il n’a pas encore vus, ce qui compte pour les conteneurs déjà en cours d’exécution (et déjà en train de journaliser) avant la configuration de cette source ; sans cela, Fluentd ne récupère que les nouvelles lignes à partir du moment où il commence à surveiller un fichier donné.

Enrichir avec du contexte : quel conteneur, quel hôte

Les lignes de log brutes d’un conteneur n’indiquent pas d’elles-mêmes de quel pod, nœud ou conteneur elles proviennent ; ce contexte doit être ajouté, généralement avec un filter utilisant le plugin record_transformer :

<filter docker.**>
  @type record_transformer
  <record>
    hostname "#{Socket.gethostname}"
  </record>
</filter>

Ceci ajoute le nom de l’hôte courant à chaque entrée taguée sous docker., ce qui permet ensuite de savoir de laquelle de plusieurs réplicas, derrière un répartiteur de charge ou sur un cluster, provient réellement une ligne de log. Le même schéma s’étend au nom du pod, au namespace ou à toute autre métadonnée qu’il vaut mieux attacher à la collecte plutôt que d’essayer de la reconstituer plus tard.

Vérifier chaque source indépendamment

Avant de brancher de vraies destinations de sortie, pointez chaque source vers un simple match @type stdout et confirmez qu’elle produit la structure attendue :

<match apache.access>
  @type stdout
</match>

Générez une requête (ou écrivez une ligne dans le fichier, ou faites un POST vers l’endpoint HTTP, ou démarrez un conteneur) et observez l’apparition de la sortie analysée et taguée. Confirmer chaque source isolément, avant d’ajouter des filtres ou de vraies destinations par-dessus, permet bien plus facilement de savoir quelle étape a introduit un problème si quelque chose plus loin dans le pipeline ne ressemble pas à ce qui est attendu.

Guides populaires