Filtrer les logs de nginx par URL, IP ou User Agent

Unix

J’ai eu besoin de filtrer les logs d’accès à mes serveurs nginx, mais je ne voulais pas d’un cron qui faisait un filtre son mon access_log, parce que j’aime les choses simples. Heureusement depuis la version 1.7 de nginx, il est possible de faire du logging conditionnel, exactement ce dont j’avais besoin !

Ainsi il est possible de faire un filtre grâce aux nombreuses variables qui existent dans nginx.

Utiliser les filtres implique de créer une map de valeur à filtrer à l’extérieur d’un block server et d’utiliser ces variables dans vos blocks server.

Filtrer par IPs

Pour filtrer des IPs vous pouvez facilement le faire en déclarant une map des IPs que vous voulez filtrer à l’extérieur de votre block server et ensuite en ajoutant une condition if=$excluded_ips à la fin de la ligne de logs.

# Map des IPs qui seront exlues des logs
map $binary_remote_addr $excluded_ips {
   "X.X.X.X" 0; # HOME
   "Y.Y.Y.Y" 0; # WORK
   default 1;
}

server {
    […]
    access_log /var/log/nginx/access_filtered.log main if=$exclude_ips;
}

Remarque : si vous êtes derrière un proxy comme Traefik, il faudra plutôt utiliser la variable $http_x_forwarded_for, sinon vous obtiendrez dans vos logs l’IP de votre proxy, ce qui est, vous le reconnaitrez, inutile.


Filtrer par URL

Pour filtrer sur les URLs, il est possible de faire du matching d’url, dans l’exemple je ne veux pas avoir de logs pour les favicons et les icônes.

# Map des urls que l'on ne veut pas logguer
map $request_uri $exclude_urls {
   ~/favicon.ico 0;
   ~/icon/* 0;
   default 1;
}

server {
    […]
    access_log /var/log/nginx/access_filtered.log main if=$exclude_urls;
}

Filtrer par User Agent

Même chose pour les User Agent,

# Map des strings qui ne doivent pas êtres contenues dans les chaines des UAs
map $http_user_agent $excluded_uas {
   ~*bot 0;
   ~*spider 0;
   ~*crawler 0;
   ~*pearltree 0;
   ~*qwantify 0;
   ~*Go-http-client 0;
   ~*AppEngine-Google 0;
   default 1;
}

server {
    […]
    access_log /var/log/nginx/access_filtered.log main if=$excluded_uas;
}

Filtrer sur plusieurs variables en même temps

Voila, ces exemples simples permettent de filtrer uniquement sur une seule variable. Si jamais vous voulez avoir un filtre avec au moins deux variables, il faudra ajouter un poil de logique dans votre block server.

J’ai appliqué la logique sur les 3 filtres que l’on a défini juste avant, cela vous permettra de comprendre la logique et de compléter le filtrage par d’autres règles si vous en avez le besoin.

 # Log
access_log  /var/log/nginx/access.log all;
error_log /var/log/nginx/error.log;
set $logging 1;
if ($exclude_urls = 0) {
   set $logging 0;
}
if ($excluded_ips = 0) {
   set $logging 0;
}
if ($excluded_uas = 0) {
   set $logging 0;
}
access_log  /var/log/nginx/filtered.log all if=$logging;

Par défaut les requêtes sont écrites dans les logs mais à la moindre condition invalide, la requête ne sera pas logguée.

Conclusion

Voila un moyen et rapide d’avoir un fichier de logs filtré sans avoir à faire de grep, sed. La seule chose à faire est de surveiller le contenu de votre fichier de log, le logrotate de temps en temps et vous avez un fichier de log filtrer sans avoir à y penser.

Vous comprendrez prochainement l’intérêt de cet article… :)

Source initiale : Exclude certain requests from the Nginx access log

Partager