lundi, octobre 1 2012

Nombre d'occurrences dans un fichier - remix

Je détaillais dans un billet écrit il y a déjà un sacré bout de temps comment obtenir une sorte de top 10 des adresses IP effectuant le plus de requêtes dans un fichier de log Apache. J'ai décidé de revenir dessus, et de faire quelques déclinaisons de ce one-liner selon les recherches. Attention si vous voulez copier-coller ces exemples, ils ont été réalisés sous NetBSD, et la commande sort n'a pas les mêmes options. Grosso modo pour le moment, j'ai vu que là où on écrit sort -g sous GNU/Linux, il faut écrire sort -n sous NetBSD. J'ai aussi décidé de me limiter à un top 5 dans l'affichage, afin d'éviter un billet trop long.

Revenons donc d'abord sur le one-liner de base, les IP qui font le plus de requêtes, avec à gauche, l'adresse IP, et à droite le nombre de hits :

root@dev:/var/log/httpd# awk '{frequencies[$1]++;} END {for (field in frequencies) printf "%s\t%d\n" , field , frequencies[field];}' < ./access.log | sort -nr -k 2,2 | head -5
81.X.Y.Z    6414
208.F.B.I 1578
178.K.G.B  1301
67.D.S.T  1179
77.C.I.A     1157

Ensuite, effectuons pareil mais sur les URLs visitées, toujours avec le nombre de hits à droite :

root@dev:/var/log/httpd# awk '{frequencies[$7]++;} END {for (field in frequencies) printf "%s\t%d\n" , field , frequencies[field];}' < ./access.log | sort -nr -k 2,2 | head -5
/post/2008/05/17/installation-de-phpmyadmin-sur-CentOS-5        7787
/post/2008/05/24/Installation-de-mod_gnutls-sur-CentOS-5        4010
/post/2008/06/20/Utilisateurs-virtuels-sous-CentOS-5-avec-base-de-donnees-MySQL 1910
/post/2007/11/28/Installation-et-configuration-dun-serveur-dedie-OpenArena-071  1284
/post/2009/11/09/Utilisation-transparente-d-une-passerelle-SSH  1266

Comme il ne s'agit que de modifier le numéro du champ, on peut aussi voir les codes de retour HTTP les plus obtenus :

root@dev:/var/log/httpd# awk '{frequencies[$9]++;} END {for (field in frequencies) printf "%s\t%d\n" , field , frequencies[field];}' < ./access.log | sort -nr -k 2,2 | head -5
200     57019
304     6156
404     1797
500     114
403     20

On peut ensuite aller chercher avec grep les pages causant des erreurs 500 ou 404.

Toujours avec la même facilité (un simple numéro de champ à modifier), on peut afficher les referers qui amènent le plus de hits :

root@dev:/var/log/httpd# awk '{frequencies[$11]++;} END {for (field in frequencies) printf "%s\t%d\n" , field , frequencies[field];}' < ./access.log | sort -nr -k 2,2 | head -5
"-"     44306
"http://blog.anotherhomepage.org/post/2008/05/17/installation-de-phpmyadmin-sur-CentOS-5"       3443
"http://blog.anotherhomepage.org/post/2008/06/20/Utilisateurs-virtuels-sous-CentOS-5-avec-base-de-donnees-MySQL"        686
"http://blog.anotherhomepage.org/post/2009/11/09/Utilisation-transparente-d-une-passerelle-SSH" 552
"http://www.google.fr/search?q=phpmyadmin+centos&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:fr:official&client=firefox-a"   401

On remarque que beaucoup n'ont pas de referer, mais il est probable que ce soient des hits sur le flux RSS. On remarque aussi que j'ai beaucoup de referers de mon propre site, il me suffit de les filtrer si je ne veux pas les afficher. Afin de rendre le traitement plus rapide, je décide de mettre la commande grep en premier dans mon traitement :

root@dev:/var/log/httpd# grep -v "blog.anotherhomepage.org" access.log | awk '{frequencies[$11]++;} END {for (field in frequencies) printf "%s\t%d\n" , field , frequencies[field];}' | sort -nr -k 2,2 | head -5
"-"     44306
"http://www.google.fr/search?q=phpmyadmin+centos&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:fr:official&client=firefox-a"   401
"http://www.google.fr/search?q=centos+phpmyadmin&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:fr:official&client=firefox-a"   166
"http://forum.hardware.fr/hfr/OSAlternatifs/Installation/resolu-centos-phpmyadmin-sujet_70143_1.htm"    121
"http://www.google.fr/" 77

Reprenons notre affichage des URLs les plus visitées, mais cette fois prenons en compte les méthodes (GET, HEAD, POST) et la version du protocole HTTP :

root@dev:/var/log/httpd# awk -F "\"" '{frequencies[$2]++;} END {for (field in frequencies) printf "%s\t%d\n" , field , frequencies[field];}' < ./access.log | sort -nr -k 4| head -5
GET /post/2008/05/17/installation-de-phpmyadmin-sur-CentOS-5 HTTP/1.1   4266
GET /post/2008/05/17/installation-de-phpmyadmin-sur-CentOS-5 HTTP/1.0   3521
GET /post/2008/05/24/Installation-de-mod_gnutls-sur-CentOS-5 HTTP/1.1   2181
GET /post/2008/05/24/Installation-de-mod_gnutls-sur-CentOS-5 HTTP/1.0   1829
GET /post/2008/06/20/Utilisateurs-virtuels-sous-CentOS-5-avec-base-de-donnees-MySQL HTTP/1.0    1193

On note ici l'utilisation de l'option "-F" de awk pour changer le motif du séparateur de champ, ce qui me permet d'avoir des champs avec espace.

Enfin, dernier exemple, trions maintenant les User-Agents :

root@dev:/var/log/httpd# awk -F "\"" '{frequencies[$6]++;} END {for (field in frequencies) printf "%d\t%s\n" , frequencies[field], field;}' < ./access.log | sort -nr | head -5
10539   Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1) VoilaBot BETA 1.2 (support.voilabot@orange-ftgroup.com)
6493    Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320; SPV M700; OpVer 19.123.2.733) OrangeBot-Mobile 2008.0 (mobilesearch.support@orange-ftgroup.com)
4188    Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp)
3269    msnbot/2.0b (+http://search.msn.com/msnbot.htm)
3017    Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)

J'ai décidé cette fois-ci d'afficher le nombre d'occurrences à gauche, car le nombre de champs (séparés par un espace) n'est plus fixe dans le cas des User-Agents. Mais au moment d'écrire cette phrase, j'ai de nouveau parcouru la page de manuel de sort et j'ai pu voir qu'il est possible de spécifier le séparateur de champ (option -t). J'ai utilisé le caractère $ pour séparer le nombre d'occurrences du libellé du User-Agent, suivi de 'tr' pour le remplacer par une tabulation :

awk -F "\"" '{frequencies[$6]++;} END {for (field in frequencies) printf "%s$%d\n" , field , frequencies[field];}' < ./access.log | sort -nr -t$ -k 2,2| tr $ "\t" | head -5
Mozilla/5.0 (Windows; U; Windows NT 5.1; fr; rv:1.8.1) VoilaBot BETA 1.2 (support.voilabot@orange-ftgroup.com)  10539
Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; PPC; 240x320; SPV M700; OpVer 19.123.2.733) OrangeBot-Mobile 2008.0 (mobilesearch.support@orange-ftgroup.com)        6493
Mozilla/5.0 (compatible; Yahoo! Slurp/3.0; http://help.yahoo.com/help/us/ysearch/slurp) 4188
msnbot/2.0b (+http://search.msn.com/msnbot.htm) 3269
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)        3017

Le choix du caractère de séparateur de champ est discutable, mais il ne change pas qu'après réflexion, l'affichage de la commande précédente me semble plus lisible. Et je pense qu'afficher le nombre d'occurences en permier sera plus lisible dans d'autres cas, comme le referer ou l'URL.

lundi, mars 1 2010

Nombre d'occurences d'un champ dans un fichier

Après la coloration d'un grep pour une histoire de cron, voici un autre cas sympathique : je souhaitais savoir qui faisait le plus de requêtes sur un serveur web (Apache), avec un classement. Un genre de top 5 ou top 10 des plus gros requêteurs de pages sur le dit serveur, en somme. J'ai cherché du côté de Awk, qui permet de manipuler à loisir les sorties de programmes et autres fichiers textes.

Comme je ne suis pas très doué en Awk, j'ai demandé à mon moteur de recherche favori (qui n'est plus Goo... d'ailleurs) comment obtenir le nombre d'occurrences d'une chaîne de caractères. La réponse se trouvait . Par contre pour faire mon top 10, il me fallait ensuite trier la liste obtenue en utilisant le nombre d'occurrences comme critère. Après quelques pipelines et autres awk hasardeux, j'en suis venu à ça :

awk '{frequencies[$1]++;} END {for (ip in frequencies) printf "%d\t%s\n" , frequencies[ip] , ip;}' < /mon/fichier/de/log/apache | sort -gr | head -10

Grâce à Awk, j'obtiens une sortie avec d'abord le nombre de requêtes, puis l'adresse ip. J'envoie ensuite cette sortie dans sort, dont l'option -g permet de faire des tris sur des nombres et l'option -r permet d'inverser le tri. Pour finir, head me permet de limiter mon classement aux 10 meilleurs. Cette ligne ne me satisfait pas complètement, car j'ai d'abord le nombre de requêtes, puis l'adresse IP. j'aurais aimé trouver une solution élégante mais tout ce que j'ai pu faire c'est invoquer à nouveau awk après le sort. Si quelqu'un a une idée, je suis preneur ;-)

Propulsé par Dotclear