Piwik : importer depuis les logs

Si vous avez la main sur votre serveur, Piwik met à votre disposition un script Python qui vous permet d'importer les statistiques (visites, pages vues, ...) depuis les logs de votre httpd (support Apache, Nginx, IIS et tous les autres vi vous spécifiez les regex qui vont bien). Piwik agit comme Webalizer AWStats.

Table des matières

Avantages/Inconvénients

Quels sont les avantages par rapport au traqueur JS ?

  • L'information a déjà été produite par le démon http, pourquoi la produire à nouveau avec le traqueur JS ?
  • Vos visiteurs gagnent en temps de chargement (deux requêtes de moins).
  • Vous libérez votre serveur dans les moments de forte charge (quand il y a les visites quoi) et vous calculez vos stats dans un moment de faible charge (typiquement la nuit mais ce n'est pas toujours le cas).

Quels sont les inconvénients par rapport au traqueur JS ?

  • La doc nous dit plus complexe à mettre en place ... ça se discute.
  • Avec le traqueur JS, on ne comptabilise que les visites provenant d'humains + des quelques bots qui interprètent le Javascript. Avec les logs, on comptabilise tout. SI votre site est scanné par les bots, vos stats vont perdre énormément de leur fiabilité. C'est clairement le point noir de l'analyse de logs. Même sur un tout petit blog comme celui-ci les stats perdent de leur valeur car des robots scan en continue et tentent de poster des commentaires ...

Faire tourner les logs

Pourquoi

Il est nécessaire de faire tourner les logs de votre httpd avant de lancer le script d'import sur celui-ci car, dans le cas contraire, les visites seront dédoublées par Piwik. Comme un exemple vaut mieux qu'un long discours :
Exemple de statistique dédoublée

Notez le "2x" alors que la page n'a en réalité été visité qu'une seule fois dans cet exemple.

De plus, si vous ne faîtes pas tourner les logs, vous aurez une quantité toujours plus importante à parser : les logs de la veille + les logs d'aujourd'hui ...

Comment

Pour faire tourner les logs, nous allons utiliser logrotate. Pour cela, il suffit de créer un fichier /etc/logrotate.d/apache (vérifiez qu'il n'existe pas déjà, vous aurez juste à adapter weekly/monthly => daily) avec le contenu suivant :

/var/log/apache2/GGS/*.log {
        daily
        missingok
        rotate 365
        compress
        delaycompress
        ifempty
        create 640 root adm
        sharedscripts
	olddir /var/log/archives/apache2/GGS
        postrotate
                /usr/sbin/apache2ctl graceful > /dev/null
        endscript
}

Ainsi, dans cet exemple, les logs situés dans le dossier /var/log/apache2/GGS (pensez à adapter) seront tournés tous les jours, stockés dans /var/log/archives/apache2/GGS pendant 365 jours sous forme compressée à partir de la deuxième rotation.

Configurer l'import

Il suffit de créer un fichier dans /etc/cron/daily.d/ qui fera, ainsi, appel au script d'import une fois par jour :

#!/bin/sh
 
/usr/bin/python2.6 /var/www/piwik/misc/log-analytics/import_logs.py --url="http://stats.guiguishow.info" --idsite=3 `date +/var/log/archives/apache2/GGS/access.log-\%Y\%m\%d`

Les deux paramètres obligatoires sont url et idsite. Le premier permet d'indiquer sur quel domaine se trouve Piwik (pensez à utiliser https ou toute autre méthode de sécurisation du canal si les deux domaines ne sont pas sur la même machine). L'autre permet d'indiquer l'id du site concerné. Ce dernier peut-être récupéré dans l'interface de Piwik.

Vient ensuite le nom du log à parser. Chaque jour, logrotate placera, dans /var/log/archives/apache2/GGS, le log de la veille sous le nom access.log-date_du_jour.

Concernant le nom que vous donnerez à ce script, prenez en considération le fait que c'est run-parts qui est chargé, par cron, de l'exécution des scripts. Or, comme l'explique son man, run-parts lance les scripts par ordre lexicographique. Il faut que le script logrotate passe avant notre script pour produire le log que nous allons parser. Donc il faut donner un nom "plus grand" à notre script. Dans mon cas : piwik-import.

ÉDIT du 26/11/2012 à 04h45 : Comme le signale Antoine dans les commentaires, créer une deuxième entrée dans cron n'est pas la meilleure méthode. En effet, logrotate permet de lancer une ou plusieurs commandes après la rotation des logs avec la directive "postrotate". D'ailleurs, je m'en sert pour relancer Apache. C'est donc dans cette directive qu'il fait sens d'ajouter la commande de l'import piwik (/usr/bin/python2.6 /var/www/piwik/misc/log-analytics/import_logs.py ...). Fin de l'édit

Règler les problèmes

Log SSL : Fatal error: Cannot guess the logs format.

En effet, alors que je n'ai pas changé de format de log dans ma config Apache entre mon virtualhost http et mon virtualhost https, Piwik me crache cette erreur.

Pour résoudre ce problème, il suffit de forcer le format de log avec le paramètre "--log-format-name=ncsa_extended".

Les FAI n'apparaissent pas, ils sont tous marqués "IP"

D'après la documentation, les FAI sont déduis en effectuant une requête DNS inversée sur l'adresse IP du visiteur. Néanmoins, comme cela est consommateur de ressource, le script d'import désactive cette fonction par défaut.

Pour résoudre ce problème, il suffit d'activer la fonctionnalité avec le paramètre : "--enable-reverse-dns".

Bien entendu, et je parle surtout pour un chroot, il faut qu'Apache ait accès à une bibliothèque de résolution DNS et qu'il y ait un fichier resolv.conf dans le chroot.

La géolocalisation ne marche pas : le pays du visiteur n'apparaît pas !

La doc répond déjà à ça. Avec le traqueur JS, Piwik détermine la localisation grâce au header "Accept-Language" envoyé par votre navigateur. Avec les logs, cette information n'est plus disponible.

Pour résoudre le problème, il faut installer l'extension GeoIP de Piwik ainsi que l'extension PECL GeoIP (vous avez le choix mais cette extension est la plus adaptée pour l'analyse de log, selon la documentation).

Installation de l'extension PECL GeoIP

Pour l'installer sous Debian :

apt-get install php5-geoip

On modifie ensuite la configuration de PHP (/etc/php5/apache2/php.ini) pour y ajouter (on remplacera le chemin ...) :

geoip.custom_directory=/path/to/piwik/misc

On récupère la base de donnée de correspondance entre une IP et sa géolocalisation, on la décompresse et on la range où il faut sous le nom qu'il faut :

wget -c http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz
mv GeoLiteCity.dat.gz /path/to/piwik/misc/GeoIPCity.dat
Installation du plugin GeoIP de Piwik

Attention, à partir de la version 1,9, ce plugin est inclu d'office, vous n'avez pas à l'installer ni à l'activer. Vous devez juste vérifier que c'est bien l'extension PECL qui est utilisée.

On télécharge, décompresse et on range au bon endroit :

wget -c http://dev.piwik.org/trac/attachment/ticket/45/GeoIP.zip?format=raw -O GeoIP.zip
unzip GeoIP.zip
cp -R GeoIP/ /path/to/piwik/misc/

Il ne reste plus qu'à aller dans l'interface de Piwik, rubrique Paramètres, rubrique Plugins et à activer Geolocation.

Il faut ensuite aller dans l'onglet Geolocation qui vient d'apparaître et vérifier que c'est bien l'extension PECL qui est utilisée.

Voilà, pour les prochaines visites, la géolocalisation fonctionnera.

Si vous voulez que les anciennes visites soient reconsidérées, il faut utiliser le script geoipUpdateRows.php en ligne de commande (php geoipUpdateRows.php). À partir de la version 1.9, il se trouve dans /path/to/piwik/misc/others/geoipUpdateRows.php . Si vous avez installé le plugin vous-même, il se trouve dans /path/to/piwik/plugins/GeoIP/geoipUpdateRows.php .

Il faudra ensuite vous connecter à votre base de données et supprimer toutes les tables commençant par "piwik_archive_". En actualisant l'interface de Piwik, vous devrez voir les pays de vos visiteurs.

Bien entendu, et je parle surtout pour un chroot, il faut qu'Apache ait accès à une bibliothèque de résolution DNS et qu'il y ait un fichier resolv.conf dans le chroot.

J'utilise WordPress et il y a plein de statistiques inutiles !

En effet, il y a des requêtes internes à WordPress (wp-cron), les requêtes liées à l'administration (wp-admin), ... Il est possible d'exclure des user-agents (--useragent-exclude) et des chemins (--exclude-path / --exclude-path-from) avec le script d'import.

Pour éliminer les requêtes concernant wp-cron et l'administration, quelque chose comme cela suffira : "--exclude-path=/wp-[ac]*"

J'utilise WordPress et je vois encore les requêtes concernant le flux RSS

C'est l'inconvénient du parsing de log : on voit tout. On peut néanmoins résoudre le problème mais cela se fait en deux temps.

Dans un premier temps, on filtre */feed*, ce qui permettra d'exclure les urls comme :

  • www.guiguishow.info/feed/
  • www.guiguishow.info/feed
  • www.guiguishow.info/2012/11/03/piwik-importer-depuis-les-logs/feed/ (très utilisé par les bots spammeurs pour vérifier si leur commentaire est posté).

Pour ce faire : "--exclude-path=*/feed*"

Vous allez vous apercevoir qu'il reste encore des visites avec comme chemin "?feed=rss2". Vous allez tenter de les exclure avec une regex mais cela ne fonctionnera pas.

Pour essayer de comprendre, j'ai étudié le code source et j'ai placé des affichages sauvages un peu partout pour voir les chemins traités à chaque étape. J'ai trouvé que ces URLs ne sont jamais passées dans le filtre "exclude". Même en fin de processus, au moment où les hits sont mis dans la queue finale avant envoi, elles n'apparaissent pas (hit.path n'est jamais égal à "?feed=rss2"). En revanche, le referrer de certaines requêtes correspondent avec la chaîne recherchée.

J'en deduis que, indépendamment du script d'import, si Piwik voit une url de votre site en referrer, il l'ajoute en hit même si aucune requpete n'y correspond. Ça parait logique : si cette url apparaît en referrer, alors le visiteur a consulté cette url auparavant. Bien sûr, ce raisonnement se heurte aux referrer modifiés volontairement.

La seule idée qu'il me vient est la suivante : par défaut, c'est-à-dire si vous n'avez pas activé l'option "--enable-http-redirects", les redirections HTTP (301, 302, autres 3xx sauf 304) sont exclues des logs. Nous allons donc rediriger /?feed=rss2 vers /feed/ que nous avons déjà exclu. La redirection ?feed=rss2 -> /feed/ sera ignorée et la consultation de /feed/ qui suivra sera tout aussi ignorée. Ainsi ces hits n'apparaîtront pas dans vos stats et votre visiteur sera redirigé de manière transparente.

Cela peut se faire avec un rewrite mais j'ai choisi de le faire avec la directive RedirectMatch disponible dans le mod alias. Il suffit de spécifier ça dans la configuration d'Apache :

RedirectMatch ^/?feed=rss2$ /feed/

Mais je vois encore mes visites sur les pages "normales"

Là encore, c'est l'inconvénient du parsing de log. Le cookie d'exclusion ne peut pas être utilisé puisqu'il n'apparaît pas dans les logs. L'exclusion de votre IP dans l'interface de Piwik ne fonctionne pas avec le script d'impot.

Si vous avez une IP fixe, on peut toujours imaginer un filtrage avec "grep -v" avant de passer le fichier de log ainsi traité au script d'import.

On peut imaginer une exclusion basée sur un user agent (--useragent-exclude) spécifique qu'une extension Firefox vous ferez prendre uniquement sur votre site.

Bref, on peut imaginer plein de choses mais il faut voir si c'est réalisable et si ce n'est pas utiliser un bazooka pour écraser une mouche 😉 .

Sources

4 commentaires pour le moment

Ajoutez votre commentaire
  1. Hello,

    Merci pour l’article 🙂
    P’tite question, qu’est-ce qui fait que tu n’utilises pas la directive « postrotate » dans la conf de logrotate pour apache (pour lancer l’import) plutôt que de créer une nouvelle entrée dans cron.daily ?

    • Plop,

      Parce que je n’y ai pas pensé ? 😛

      La remarque est exacte, je vais ajouter une note à l’article. Merci.

  2. Merci pour ces infos détaillées.
    Je me demandais s’il était possible de compléter le log Apache2 avec le header %{Accept-Language}i et le cookie d’exclusion %{LeNomDuCookie}C pour résoudre les problèmes mentionnés.
    Il est possible que le script d’import python ait besoin de modifications ensuite mais ça pourrait valoir la peine.

  3. Article interessant merci

    > L’exclusion de votre IP dans l’interface de Piwik ne fonctionne pas avec le script d’impot.

    notez que l’import de logs va respecter l’exclusion des addresses IP, a condition que les IPs soient correctes dans le fichier de log