Statistiques Apache
Par Gilles le jeudi 1 mars 2007 - Geekeries - Lien permanent
Pour surveiller un peu son serveur web, faire des statistiques pour voir quel sont les pages les plus demandées (ou quels sont les sites les plus consultés, en cas de Virtual Hosting), on dispose d'outils qui analysent les logs d'Apache. Par exemple, Analog et Webalizer. Tous ces programmes ont en communs qu'ils viennent chercher leur informations dans les logs d'Apache, et affichent de beaux histogrammes en fonction de ça. Pour ma part j'ai porté mon choix sur webalizer.
J'ai remarqué que par défaut, apache2 avait un soucis: si un transfert est interrompu, il note la taille du fichier demandé. Ainsi, prenons un fichier de 1 Go, qui serait téléchargé par un utilisateur. Il commence à charger le fichier, et il arrête le transfert au bout d'un méga. Aussitôt la réception de l'ordre d'arrêt, Apache2 va s'empresser de logguer fièrement que le fichier de 1 Go a été transféré. Or, seulement 1 Mo a été envoyé !
Toujours avec le même exemple, mettons qu'un download manager charge le fichier. Il n'est pas rare qu'il fractionne le fichier en bouts de 5 Mo, et lance plusieurs transferts en même temps. But de la manoeuvre ? Franchement, à part surcharger le serveur et empêcher d'autres utilisateurs de charger le fichier, je ne vois pas... Donc, le fichier de 1 Go se verra découpé en 200 bouts de 5 Mo. Et Apache devra donc envoyer 200 fois un bout de fichier de 5 Mo. Problème: à la fin de chaque bout, il sera loggué qu'un fichier de 1 Go a été transféré ! Traffic total pour ce fichier: 200 Go !!! Alors que seul 1 Go a transité ! Et voilà, les outils de statistiques sont faussés, et la bande passante calculée devient complétement fantaisiste.
A qui la faute ? A Apache ! En effet, si on croit cette page, "Note that in httpd 2.0, unlike 1.3, the %b and %B format strings do not represent the number of bytes sent to the client, but simply the size in bytes of the HTTP response (which will differ, for instance, if the connection is aborted, or if SSL is used). The %O format provided by mod_logio will log the actual number of bytes sent over the network."
Voilà !
Donc la solution est simple : dans apache2.conf, remplacer les lignes:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
par:
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %O" common
L'utilisation de %O nécessite la présence de mod_logio (qui est par défaut sur debian). Cette modification est suffisante, si vous utilisez les CustomLog combined ou common.
Je profite de cet espace pour indiquer un autre truc: si vous avez séparé vos logs en fonction de vos Virtual Host (chaque Virtual Host a donc son fichier de log indépendant), et que vous générez différentes pages de statistiques pour chaque Virtual Host, il peut être intéressant de merger tous les fichiers de logs ensemble pour avoir une page cumulant tous les hotes virtuels.
Pour cela, dans la définition de vos Virtual Hosts, mettez deux lignes CustomLog, comme ceci:
CustomLog /home/web/admin/apache-logs/access.log combined env=!dontlog CustomLog /var/log/apache2/access.log combined env=!dontlog
Ainsi, chaque page chargée générera une ligne de log dans deux fichiers. C'est redondant, mais ca reste plus léger que d'utilise mergelog à chaque appel de webalizer.
Ah, vous vous demandez ce que fait "env=!dontlog" ? Eh bien dans apache2.conf, j'ai rajouté la ligne:
SetEnvIf Remote_Addr "127\.0\.0\.1" dontlog
Ainsi, toutes les requetes provenant de 127.0.0.1 ne sont pas loguées. On peut étendre ça de façon à ne pas loguer certaines pages, par exemple en ajoutant juste après cette ligne:
SetEnvIf Request_URI "^/admin" dontlog
on ne logguera pas les fichiers transférés dont l'adresse commence par /prv/
Voilà, enfin des statistiques avec des vrais chiffres qui veulent dire quelque chose !