Générer des fichiers métriques avec la moulinette statoolinfos

Pour générer les fichiers properties de la version 0.4 de ChatonsInfos, deux méthodes :

  • extraire des stats d’un collecteur de stats (Matomo, Grafana…) et les convertir au format properties ChatonsInfos ;
  • lancer une moulinette qui va lire directement les logs, les analyser et les convertir au format properties ChatonsInfos.

La moulinette StatoolInfos est une proposition pour la deuxième approche. Pour l’instant, seules les logs HTTP sont analysées. L’idée est de progressivement ajouter l’analyse des métriques spécifiques des services.

StatoolInfos reconnait les logs Nginx et Apache (format combined). Pour des formats de logs personnalisés, un support de regex personnalisée et en cours de développement.

Liens :

À vos métriques, prêt, partez ! :smiley_cat:

3 Likes

Bonjour @Cpm et merci pour ce travail !

Sur ISPconfig (que j’utilise) le rangement des logs est fait comme ceci :

root@srvweb:~/statoolinfos-conf# ls -la /var/www/dl.zici.fr/log/
total 960
drwxr-xr-x 2 root root 4096 déc. 18 03:37 .
drwxr-xr-x 11 root root 4096 nov. 8 2020 …
-rw-r–r-- 1 root root 15834 déc. 9 00:28 20211207-access.log.gz
-rw-r–r-- 1 root root 28470 déc. 10 00:30 20211208-access.log.gz
-rw-r–r-- 1 root root 24001 déc. 11 00:29 20211209-access.log.gz
-rw-r–r-- 1 root root 21597 déc. 12 00:39 20211210-access.log.gz
-rw-r–r-- 1 root root 15420 déc. 13 00:31 20211211-access.log.gz
-rw-r–r-- 1 root root 10365 déc. 14 00:26 20211212-access.log.gz
-rw-r–r-- 1 root root 15214 déc. 15 00:35 20211213-access.log.gz
-rw-r–r-- 1 root root 19990 déc. 16 00:40 20211214-access.log.gz
-rw-r–r-- 1 root root 12761 déc. 17 00:31 20211215-access.log.gz
-rw-r–r-- 1 root root 18669 déc. 18 00:42 20211216-access.log.gz
-rw-r–r-- 1 root root 468003 déc. 17 23:58 20211217-access.log
-rw-r–r-- 1 root root 105890 déc. 18 20:10 20211218-access.log
lrwxrwxrwx 1 root root 19 déc. 18 03:37 access.log → 20211218-access.log
-rw-r–r-- 1 root root 67701 déc. 18 20:10 error.log
-rw-r–r-- 1 root root 10190 déc. 9 00:28 error.log.10.gz
-rw-r–r-- 1 root root 17420 déc. 18 00:42 error.log.1.gz
-rw-r–r-- 1 root root 8571 déc. 17 00:31 error.log.2.gz
-rw-r–r-- 1 root root 6600 déc. 16 00:40 error.log.3.gz
-rw-r–r-- 1 root root 8409 déc. 15 00:35 error.log.4.gz
-rw-r–r-- 1 root root 6011 déc. 14 00:26 error.log.5.gz
-rw-r–r-- 1 root root 5604 déc. 13 00:31 error.log.6.gz
-rw-r–r-- 1 root root 6260 déc. 12 00:39 error.log.7.gz
-rw-r–r-- 1 root root 8820 déc. 11 00:29 error.log.8.gz
-rw-r–r-- 1 root root 13520 déc. 10 00:30 error.log.9.gz
lrwxrwxrwx 1 root root 55 déc. 18 00:20 yesterday-access.log → /var/www/clients/client3/web230/log/20211217-access.log

Seulement si dans la config j’indique :

conf.probe.types=HttpAccessLog, HttpErrorLog
conf.probe.httpaccesslog.file=/var/www/dl.zici.fr/log/access.log
conf.probe.httperrorlog.file=/var/www/dl.zici.fr/log/error.

Voici ce qu’il me dit avec « probe -full » :

Probing [/root/zici/statoolinfos-conf/statoolinfos-dl.zici.fr.conf] with day count filter 1
Probe /root/zici/statoolinfos-conf/statoolinfos-dl.zici.fr.conf
Targets=[HttpAccessLog][HttpErrorLog]
== Processing HttpAccessLog.
source=[/var/www/dl.zici.fr/log/*access.log]
pattern=[null]
Probing file [/var/www/dl.zici.fr/log/*access.log]
Error with [/root/zici/statoolinfos-conf/statoolinfos-dl.zici.fr.conf]: /var/www/dl.zici.fr/log/*access.log (Aucun fichier ou dossier de ce type)
java.io.FileNotFoundException: /var/www/dl.zici.fr/log/*-access.log (Aucun fichier ou dossier de ce type)
	at java.base/java.io.FileInputStream.open0(Native Method)
	at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
	at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157)
	at fr.devinsy.statoolinfos.util.LineIterator.<init>(LineIterator.java:61)
	at fr.devinsy.statoolinfos.metrics.http.HttpAccessLogAnalyzer.probe(HttpAccessLogAnalyzer.java:149)
	at fr.devinsy.statoolinfos.metrics.http.HttpAccessLogAnalyzer.probe(HttpAccessLogAnalyzer.java:426)
	at fr.devinsy.statoolinfos.metrics.Prober.probe(Prober.java:115)
	at fr.devinsy.statoolinfos.metrics.Prober.probe(Prober.java:223)
	at fr.devinsy.statoolinfos.core.StatoolInfos.probe(StatoolInfos.java:330)
	at fr.devinsy.statoolinfos.cli.StatoolInfosCLI.run(StatoolInfosCLI.java:425)
	at fr.devinsy.statoolinfos.StatoolInfosLauncher.main(StatoolInfosLauncher.java:70)

Tu as une idée du pourquoi ?

Rien de trop méchant, ça marche en retirant « * » sur l’access.log et « probe -previousday » :

conf.probe.types=HttpAccessLog, HttpErrorLog
conf.probe.httpaccesslog.file=/var/www/dl.zici.fr/log/access.log
conf.probe.httperrorlog.file=/var/www/dl.zici.fr/log/error.*
conf.probe.target=/var/www/zici.fr/web/.well-known/chatonsinfos/organizations.default/service-dl.metrics

Note : je sais pas où tu préfère les tickets pour ça, ta forge semble pas être ouverte aux inscriptions…

1 Like

Tu as une idée du pourquoi ?

Oui … j’ai juste prévu le « * » à la fin des chemins, pas à leur début ! :scream_cat:

Je vais m’en occuper. Comme quoi ton retour d’expérience est très utile :star_struck: Un grand merci à toi :smiley:

ça marche en retirant « * » sur l’access.log et « probe -previousday »

Oui, on commence même à voir le début de tes métriques sur stats.chatons.org, c’est top :sunglasses: :partying_face:

Note : je sais pas où tu préfère les tickets pour ça, ta forge semble pas être ouverte aux inscriptions…

Je confirme que le dépôt officiel est sur ma forge. Dans Gitea, la modération a priori des créations de comptes est buggée, du coup je préférais les faire sur demande.

Je viens de réactiver les inscriptions, tu peux y retourner. Je serai honoré de recevoir tes tickets :hugs:

Cher @kepon, merci pour le ticket. La nouvelle release contient un correctif qui prend mieux en compte les wildcards.

Je t’invite à relancer la commande en mode -full :smiley:

1 Like

C’est fait, c’est beau… :wink:

1 Like

Coucou les développeurs de statoolinfos,

Bravo pour le travail réalisé :sunglasses:.

Par contre, vu que l’ensemble de mes outils d’administration de services sont en Python, j’ai retraduit cet outil dans ce langage.
C’est bien plus souple pour moi d’appeler dans mon code Python mes packages Statoolinfos que de devoir faire un appel à une commande système pour le rebranché sur l’outil en Java.
=> Je le met bien au propre et je diffuserais aussi mon outil pour ceux que cela intéresse :wink: .

Suite à ma plongé dans le code, j’ai quelques petites remarques sur l’impémentation.

Dans « fr/devinsy/statoolinfos/metrics/http/HttpAccessLogAnalyzer.java » (ligne 392), on a:
result.setTime(LocalDateTime.parse(matcher.group("time"), DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z").withLocale(Locale.ENGLISH)));

Or, je suis dans un cas où mes logs ont leur date en français et même que j’ai vu des cas où le mois était écris soit en mot complet, soit en abrégé.
J’ai donc fait une fonction (Python) de ce genre pour gérer tout les cas possible:

def convert_datetime(timetext):
    import locale
    saved = locale.setlocale(locale.LC_ALL)
    try:
        locale.setlocale(locale.LC_ALL, 'C')
        try:
            return datetime.strptime(timetext, "%d/%B/%Y:%H:%M:%S %z")
        except ValueError:
            pass
        try:
            return datetime.strptime(timetext, "%d/%b/%Y:%H:%M:%S %z")
        except ValueError:
            pass
        try:
            return datetime.strptime(timetext, "%Y/%m/%d %H:%M:%S")
        except ValueError:
            pass
        locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8')
        try:
            return datetime.strptime(timetext, "%d/%B/%Y:%H:%M:%S %z")
        except ValueError:
            pass
        try:
            return datetime.strptime(timetext, "%d/%b/%Y:%H:%M:%S %z")
        except ValueError:
            pass
        print("bad datetime:", timetext, file=sys.stderr)
    finally:
        locale.setlocale(locale.LC_ALL, saved)

Si je n’arrive pas à décoder la date, je retourne pas de date et donc j’igore la ligne de log.

J’ai corrigé également un autre point, la methode « UserAgent.getOS() » (fichier « fr/devinsy/statoolinfos/metrics/http/UserAgent.java », ligne 109).
En effet, on recherche des mots liés au navigateur et pas au système d’exploitation dans la chaine « source ».
J’ai donc implémenté (en Python) comme cela:

def getOS(self):
    if "Android" in self.source:
        result = "android"
    elif "Mac OS X" in self.source:
        result = "macosx"
    elif "Linux" in self.source:
        result = "gnulinux"
    elif "Windows" in self.source:
        result = "windows"
    else:
        result = "other"
    return result

A revoir pour améliorer d’autres recherches et que tout le monde aient bien les mêmes OS retour.

Une dernière remarque.
Dans la « moulinette », on sauve dans les « PathCounters »: year, yearMonth, yearWeek, date.
Or, le premier élément « year » n’est jamais exploité.
En effet, notre standard de propriété n’accepte pas des metriques de la forme http.xxxx.2022.year
On a donc un traitement inutile, non exploité, dans l’outil.
A voir si on l’intégre comme une metric supplémentaire ou si on simplifie nos traitements.

Voilà pour mon retour.
En tout cas bravo pour le travail, l’outil est bien fait et le code facile à comprendre.
Par exemple, l’algo sur les « VisitorCounters » est super: j’aurais vraiment galèré à le repenser.
Au final, j’ai vraiment pas mis longtemp pour traduire en Python :slight_smile: .

Grand merci à toute l’équipe.
Je ne manquerais pas de vous faire un autre retour sur la suite.

Laurent, un fan de stats.chatons.org :heart_eyes:

Par contre, vu que l’ensemble de mes outils d’administration de services sont en Python, j’ai retraduit cet outil dans ce langage.
C’est bien plus souple pour moi d’appeler dans mon code Python mes packages Statoolinfos que de devoir faire un appel à une commande système pour le rebranché sur l’outil en Java.

Un principe fondamental de StatoolInfos est de minimiser les barrières/contraintes/obstacles pour ceux qui gèrent les services. Si pour générer les fichiers métriques, tu te sens de ré-écrire le code dans un langage qui te convient, alors fais-le, c’est bien. Plus il y aura de méthodes et d’outils, plus il y aura de chance qu’un utilisateur trouve celui qui lui est le plus adapté :hugs:

Content de savoir que le code t’est utile :smiley:

Je le met bien au propre et je diffuserais aussi mon outil pour ceux que cela intéresse

Oui, n’hésite pas, nous le citerons dans les docs. Partage le lien du dépôt quand tu veux :slight_smile:

Or, je suis dans un cas où mes logs ont leur date en français et même que j’ai vu des cas où le mois était écris soit en mot complet, soit en abrégé.

Argh, je n’avais pas encore rencontré ce cas. Merci pour le signalement, je vais compléter.

la methode « UserAgent.getOS() »

Je confirme que cela fait partie des quelques points à finaliser avec la géolocalisation des ips, le type de terminal et d’autres. Je vais refaire un passage dessus.

Or, le premier élément « year » n’est jamais exploité.
En effet, notre standard de propriété n’accepte pas des metriques de la forme http.xxxx.2022.year. On a donc un traitement inutile, non exploité, dans l’outil.

Alors en fait si. Au début du projet, la génération des métriques annuelles était active mais impliquait d’avoir au moins 1 an de logs disponible, ce qui constitue une contrainte trop lourde. Du coup, je l’ai neutralisé tout en laissant le code au cas où (ou en attendant de savoir ce que j’allais en faire) :innocent:

À noter que notre standard de propriété pour les années est de la forme http.xxxx.2022', avec une ligne par année et une seule valeur par année. Parce que si on utilise le suffixe years`, ça impliquerait de devoir indiquer l’année initiale :yum:

Je ne manquerais pas de vous faire un autre retour sur la suite.

Avec grand plaisir. Merci pour ton implication :smiley_cat: