L'utilitaire Webalizer et l'outil Google Analytics m'ont aidé pendant de nombreuses années à me faire une idée de ce qui se passe sur les sites Web. Je comprends maintenant qu'ils fournissent trÚs peu d'informations utiles. Avoir accÚs à votre fichier access.log, gérer les statistiques est trÚs simple et pour l'implémentation d'outils assez basiques tels que sqlite, html, sql et tout langage de programmation de script.
La source de données pour Webalizer est le fichier access.log du serveur. Voici à quoi ressemblent ses colonnes et ses chiffres, dont seule la quantité totale de trafic est claire:
Des outils tels que Google Analytics collectent seuls les donnĂ©es de la page chargĂ©e. Ils nous montrent quelques schĂ©mas et lignes, sur la base desquels il est souvent difficile de tirer les bonnes conclusions. Peut-ĂȘtre que plus d'efforts Ă©taient nĂ©cessaires? Je ne sais pas.
Alors, que voulais-je voir dans les statistiques de visites sur site?
Trafic d'utilisateurs et de robots
Souvent, le trafic du site a une limite et vous devez voir combien de trafic utile est utilisé. Par exemple, comme ceci:

Demande de rapport SQLSELECT 1 as 'StackedArea: Traffic generated by Users and Bots', strftime('%d.%m', datetime(FCT.EVENT_DT, 'unixepoch')) AS 'Day', SUM(CASE WHEN USG.AGENT_BOT!='na' THEN FCT.BYTES ELSE 0 END)/1000 AS 'Bots, KB', SUM(CASE WHEN USG.AGENT_BOT='na' THEN FCT.BYTES ELSE 0 END)/1000 AS 'Users, KB' FROM FCT_ACCESS_USER_AGENT_DD FCT, DIM_USER_AGENT USG WHERE FCT.DIM_USER_AGENT_ID=USG.DIM_USER_AGENT_ID AND datetime(FCT.EVENT_DT, 'unixepoch') >= date('now', '-14 day') GROUP BY strftime('%d.%m', datetime(FCT.EVENT_DT, 'unixepoch')) ORDER BY FCT.EVENT_DT
Sur le graphique, vous pouvez voir l'activité constante des bots. Il serait intéressant d'étudier en détail les représentants les plus actifs.
Bots ennuyeux
Nous classons les bots en fonction des informations de l'agent utilisateur. Statistiques supplémentaires sur le trafic quotidien, le nombre de demandes réussies et infructueuses donne une bonne idée de l'activité des bots.

Demande de rapport SQL SELECT 1 AS 'Table: Annoying Bots', MAX(USG.AGENT_BOT) AS 'Bot', ROUND(SUM(FCT.BYTES)/1000 / 14.0, 1) AS 'KB per Day', ROUND(SUM(FCT.IP_CNT) / 14.0, 1) AS 'IPs per Day', ROUND(SUM(CASE WHEN STS.STATUS_GROUP IN ('Client Error', 'Server Error') THEN FCT.REQUEST_CNT / 14.0 ELSE 0 END), 1) AS 'Error Requests per Day', ROUND(SUM(CASE WHEN STS.STATUS_GROUP IN ('Successful', 'Redirection') THEN FCT.REQUEST_CNT / 14.0 ELSE 0 END), 1) AS 'Success Requests per Day', USG.USER_AGENT_NK AS 'Agent' FROM FCT_ACCESS_USER_AGENT_DD FCT, DIM_USER_AGENT USG, DIM_HTTP_STATUS STS WHERE FCT.DIM_USER_AGENT_ID = USG.DIM_USER_AGENT_ID AND FCT.DIM_HTTP_STATUS_ID = STS.DIM_HTTP_STATUS_ID AND USG.AGENT_BOT != 'na' AND datetime(FCT.EVENT_DT, 'unixepoch') >= date('now', '-14 day') GROUP BY USG.USER_AGENT_NK ORDER BY 3 DESC LIMIT 10
Dans ce cas, l'analyse a abouti à une décision de restreindre l'accÚs au site en ajoutant robots.txt au fichier
User-agent: AhrefsBot
Disallow: /
User-agent: dotbot
Disallow: /
User-agent: bingbot
Crawl-delay: 5
Les deux premiers robots ont disparu de la table et les robots MS sont descendus des premiĂšres lignes.
Jour et heure de la plupart des activités
Le trafic se montre. Afin de les Ă©tudier en dĂ©tail, il est nĂ©cessaire d'identifier l'heure de leur occurrence, alors qu'il n'est pas nĂ©cessaire d'afficher toutes les heures et les jours de mesure du temps. Il sera donc plus facile de trouver des requĂȘtes individuelles dans le fichier journal si vous avez besoin d'une analyse dĂ©taillĂ©e.

Demande de rapport SQL SELECT 1 AS 'Line: Day and Hour of Hits from Users and Bots', strftime('%d.%m-%H', datetime(EVENT_DT, 'unixepoch')) AS 'Date Time', HIB AS 'Bots, Hits', HIU AS 'Users, Hits' FROM ( SELECT EVENT_DT, SUM(CASE WHEN AGENT_BOT!='na' THEN LINE_CNT ELSE 0 END) AS HIB, SUM(CASE WHEN AGENT_BOT='na' THEN LINE_CNT ELSE 0 END) AS HIU FROM FCT_ACCESS_REQUEST_REF_HH WHERE datetime(EVENT_DT, 'unixepoch') >= date('now', '-14 day') GROUP BY EVENT_DT ORDER BY SUM(LINE_CNT) DESC LIMIT 10 ) ORDER BY EVENT_DT
Nous observons les heures les plus actives 11, 14 et 20 du premier jour sur le graphique. Mais le lendemain à 13 heures, les bots étaient actifs.
Activité quotidienne moyenne hebdomadaire des utilisateurs
Avec l'activitĂ© et le trafic un peu compris. La question suivante Ă©tait l'activitĂ© des utilisateurs eux-mĂȘmes. Pour de telles statistiques, de grandes pĂ©riodes d'agrĂ©gation, par exemple une semaine, sont souhaitables.

Demande de rapport SQL SELECT 1 as 'Line: Average Daily User Activity by Week', strftime('%W week', datetime(FCT.EVENT_DT, 'unixepoch')) AS 'Week', ROUND(1.0*SUM(FCT.PAGE_CNT)/SUM(FCT.IP_CNT),1) AS 'Pages per IP per Day', ROUND(1.0*SUM(FCT.FILE_CNT)/SUM(FCT.IP_CNT),1) AS 'Files per IP per Day' FROM FCT_ACCESS_USER_AGENT_DD FCT, DIM_USER_AGENT USG, DIM_HTTP_STATUS HST WHERE FCT.DIM_USER_AGENT_ID=USG.DIM_USER_AGENT_ID AND FCT.DIM_HTTP_STATUS_ID = HST.DIM_HTTP_STATUS_ID AND USG.AGENT_BOT='na' AND HST.STATUS_GROUP IN ('Successful') AND datetime(FCT.EVENT_DT, 'unixepoch') > date('now', '-3 month') GROUP BY strftime('%W week', datetime(FCT.EVENT_DT, 'unixepoch')) ORDER BY FCT.EVENT_DT
Les statistiques de la semaine montrent qu'en moyenne, un utilisateur ouvre 1,6 page par jour. Le nombre de fichiers demandés par utilisateur dans ce cas dépend de l'ajout de nouveaux fichiers sur le site.
Toutes les demandes et leurs statuts
Webalizer a toujours montré des codes de page spécifiques et a toujours voulu voir le nombre de demandes et d'erreurs réussies.

Demande de rapport SQL SELECT 1 as 'Line: All Requests by Status', strftime('%d.%m', datetime(FCT.EVENT_DT, 'unixepoch')) AS 'Day', SUM(CASE WHEN STS.STATUS_GROUP='Successful' THEN FCT.REQUEST_CNT ELSE 0 END) AS 'Success', SUM(CASE WHEN STS.STATUS_GROUP='Redirection' THEN FCT.REQUEST_CNT ELSE 0 END) AS 'Redirect', SUM(CASE WHEN STS.STATUS_GROUP='Client Error' THEN FCT.REQUEST_CNT ELSE 0 END) AS 'Customer Error', SUM(CASE WHEN STS.STATUS_GROUP='Server Error' THEN FCT.REQUEST_CNT ELSE 0 END) AS 'Server Error' FROM FCT_ACCESS_USER_AGENT_DD FCT, DIM_HTTP_STATUS STS WHERE FCT.DIM_HTTP_STATUS_ID=STS.DIM_HTTP_STATUS_ID AND datetime(FCT.EVENT_DT, 'unixepoch') >= date('now', '-14 day') GROUP BY strftime('%d.%m', datetime(FCT.EVENT_DT, 'unixepoch')) ORDER BY FCT.EVENT_DT
Le rapport affiche les demandes, pas les clics (hits), contrairement à LINE_CNT, la métrique REQUEST_CNT est considérée comme COUNT (DISTINCT STG.REQUEST_NK). L'objectif est de montrer des événements efficaces, par exemple, des bots MS interrogeant des centaines de fois par jour un fichier robots.txt et, dans ce cas, ces sondages seront comptés une fois. Cela vous permet de lisser les sauts sur le graphique.
Sur le graphique, vous pouvez voir de nombreuses erreurs - ce sont des pages inexistantes. Le résultat de l'analyse a été l'ajout de redirections à partir de pages distantes.
Demandes erronées
Pour un examen détaillé des demandes, vous pouvez afficher des statistiques détaillées.

Demande de rapport SQL SELECT 1 AS 'Table: Top Error Requests', REQ.REQUEST_NK AS 'Request', 'Error' AS 'Request Status', ROUND(SUM(FCT.LINE_CNT) / 14.0, 1) AS 'Hits per Day', ROUND(SUM(FCT.IP_CNT) / 14.0, 1) AS 'IPs per Day', ROUND(SUM(FCT.BYTES)/1000 / 14.0, 1) AS 'KB per Day' FROM FCT_ACCESS_REQUEST_REF_HH FCT, DIM_REQUEST_V_ACT REQ WHERE FCT.DIM_REQUEST_ID = REQ.DIM_REQUEST_ID AND FCT.STATUS_GROUP IN ('Client Error', 'Server Error') AND datetime(FCT.EVENT_DT, 'unixepoch') >= date('now', '-14 day') GROUP BY REQ.REQUEST_NK ORDER BY 4 DESC LIMIT 20
Cette liste contiendra tous les numéroteurs, par exemple une demande à /wp-login.php. En ajustant les rÚgles de réécriture des demandes par le serveur, vous pouvez ajuster la réponse du serveur à ces demandes et les envoyer à la page de démarrage.
Ainsi, quelques rapports simples basés sur le fichier journal du serveur donnent une image assez complÚte de ce qui se passe sur le site.
Comment obtenir des informations?
La base de données sqlite est tout à fait suffisante. Créons des tables: auxiliaire pour la journalisation des processus ETL.

Table de scĂšne, oĂč nous allons Ă©crire des fichiers journaux en PHP. Deux tableaux agrĂ©gĂ©s. CrĂ©ez un tableau quotidien avec des statistiques sur les agents utilisateurs et les statuts des demandes. Toutes les heures avec des statistiques sur les demandes, les groupes de statut et les agents. Quatre tableaux de mesures pertinentes.
Le résultat est le modÚle relationnel suivant:
Script pour créer un objet dans la base de données sqlite:
Création d'objet DDL DROP TABLE IF EXISTS DIM_USER_AGENT; CREATE TABLE DIM_USER_AGENT ( DIM_USER_AGENT_ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, USER_AGENT_NK TEXT NOT NULL DEFAULT 'na', AGENT_OS TEXT NOT NULL DEFAULT 'na', AGENT_ENGINE TEXT NOT NULL DEFAULT 'na', AGENT_DEVICE TEXT NOT NULL DEFAULT 'na', AGENT_BOT TEXT NOT NULL DEFAULT 'na', UPDATE_DT INTEGER NOT NULL DEFAULT 0, UNIQUE (USER_AGENT_NK) ); INSERT INTO DIM_USER_AGENT (DIM_USER_AGENT_ID) VALUES (-1);
Stage
Dans le cas du fichier access.log, vous devez lire, analyser et Ă©crire toutes les demandes dans la base de donnĂ©es. Cela peut ĂȘtre fait soit directement Ă l'aide du langage de script, soit Ă l'aide de sqlite.
Format du fichier journal:
Propagande clé
Lorsque les données brutes sont dans la base de données, vous devez enregistrer des clés qui ne se trouvent pas dans les tables de mesure. Il sera alors possible de construire une référence aux mesures. Par exemple, dans la table DIM_REFERRER, la clé est une combinaison de trois champs.
RequĂȘte de propagation de clĂ© SQL INSERT INTO DIM_REFERRER (HOST_NK, PATH_NK, QUERY_NK, UPDATE_DT) SELECT CLS.HOST_NK, CLS.PATH_NK, CLS.QUERY_NK, STRFTIME('%s','now') AS UPDATE_DT FROM ( SELECT DISTINCT REFERRER_HOST AS HOST_NK, REFERRER_PATH AS PATH_NK, CASE WHEN INSTR(REFERRER_QUERY,'&sid')>0 THEN SUBSTR(REFERRER_QUERY, 1, INSTR(REFERRER_QUERY,'&sid')-1) ELSE REFERRER_QUERY END AS QUERY_NK FROM STG_ACCESS_LOG ) CLS LEFT OUTER JOIN DIM_REFERRER TRG ON (CLS.HOST_NK = TRG.HOST_NK AND CLS.PATH_NK = TRG.PATH_NK AND CLS.QUERY_NK = TRG.QUERY_NK) WHERE TRG.DIM_REFERRER_ID IS NULL
La propagation vers la table de l'agent utilisateur peut contenir une logique bot, par exemple, un extrait sql:
CASE WHEN INSTR(LOWER(CLS.BROWSER),'yandex.com')>0 THEN 'yandex' WHEN INSTR(LOWER(CLS.BROWSER),'googlebot')>0 THEN 'google' WHEN INSTR(LOWER(CLS.BROWSER),'bingbot')>0 THEN 'microsoft' WHEN INSTR(LOWER(CLS.BROWSER),'ahrefsbot')>0 THEN 'ahrefs' WHEN INSTR(LOWER(CLS.BROWSER),'mj12bot')>0 THEN 'majestic-12' WHEN INSTR(LOWER(CLS.BROWSER),'compatible')>0 OR INSTR(LOWER(CLS.BROWSER),'http')>0 OR INSTR(LOWER(CLS.BROWSER),'libwww')>0 OR INSTR(LOWER(CLS.BROWSER),'spider')>0 OR INSTR(LOWER(CLS.BROWSER),'java')>0 OR INSTR(LOWER(CLS.BROWSER),'python')>0 OR INSTR(LOWER(CLS.BROWSER),'robot')>0 OR INSTR(LOWER(CLS.BROWSER),'curl')>0 OR INSTR(LOWER(CLS.BROWSER),'wget')>0 THEN 'other' ELSE 'na' END AS AGENT_BOT
Tables unitaires
Enfin, nous chargerons des tables agrĂ©gĂ©es, par exemple, une table quotidienne peut ĂȘtre chargĂ©e comme suit:
Demande de chargement agrégé SQL INSERT INTO FCT_ACCESS_USER_AGENT_DD (EVENT_DT, DIM_USER_AGENT_ID, DIM_HTTP_STATUS_ID, PAGE_CNT, FILE_CNT, REQUEST_CNT, LINE_CNT, IP_CNT, BYTES) WITH STG AS ( SELECT STRFTIME( '%s', SUBSTR(TIME_NK,9,4) || '-' || CASE SUBSTR(TIME_NK,5,3) WHEN 'Jan' THEN '01' WHEN 'Feb' THEN '02' WHEN 'Mar' THEN '03' WHEN 'Apr' THEN '04' WHEN 'May' THEN '05' WHEN 'Jun' THEN '06' WHEN 'Jul' THEN '07' WHEN 'Aug' THEN '08' WHEN 'Sep' THEN '09' WHEN 'Oct' THEN '10' WHEN 'Nov' THEN '11' ELSE '12' END || '-' || SUBSTR(TIME_NK,2,2) || ' 00:00:00' ) AS EVENT_DT, BROWSER AS USER_AGENT_NK, REQUEST_NK, IP_NR, STATUS, LINE_NK, BYTES FROM STG_ACCESS_LOG ) SELECT CAST(STG.EVENT_DT AS INTEGER) AS EVENT_DT, USG.DIM_USER_AGENT_ID, HST.DIM_HTTP_STATUS_ID, COUNT(DISTINCT (CASE WHEN INSTR(STG.REQUEST_NK,'.')=0 THEN STG.REQUEST_NK END) ) AS PAGE_CNT, COUNT(DISTINCT (CASE WHEN INSTR(STG.REQUEST_NK,'.')>0 THEN STG.REQUEST_NK END) ) AS FILE_CNT, COUNT(DISTINCT STG.REQUEST_NK) AS REQUEST_CNT, COUNT(DISTINCT STG.LINE_NK) AS LINE_CNT, COUNT(DISTINCT STG.IP_NR) AS IP_CNT, SUM(BYTES) AS BYTES FROM STG, DIM_HTTP_STATUS HST, DIM_USER_AGENT USG WHERE STG.STATUS = HST.STATUS_NK AND STG.USER_AGENT_NK = USG.USER_AGENT_NK AND CAST(STG.EVENT_DT AS INTEGER) > $param_epoch_from AND CAST(STG.EVENT_DT AS INTEGER) < strftime('%s', date('now', 'start of day')) GROUP BY STG.EVENT_DT, HST.DIM_HTTP_STATUS_ID, USG.DIM_USER_AGENT_ID
La base de donnĂ©es sqlite vous permet d'Ă©crire des requĂȘtes complexes. WITH contient la prĂ©paration des donnĂ©es et des clĂ©s. La requĂȘte principale recueille toutes les rĂ©fĂ©rences aux dimensions.
La condition ne permettra plus de charger le rĂ©cit: CAST (STG.EVENT_DT AS INTEGER)> $ param_epoch_from, oĂč le paramĂštre est le rĂ©sultat de la requĂȘte
'SELECT COALESCE (MAX (EVENT_DT), \' 3600 \ ') AS LAST_EVENT_EPOCH FROM FCT_ACCESS_USER_AGENT_DD'
La condition ne se charge que le jour complet: CAST (STG.EVENT_DT AS INTEGER) <strftime ('% s', date ('now', 'start of day'))
Le comptage des pages ou des fichiers se fait de maniĂšre primitive, en recherchant un point.
Rapports
Dans les systĂšmes de visualisation complexes, il est possible de crĂ©er un mĂ©ta-modĂšle basĂ© sur des objets de base de donnĂ©es, de gĂ©rer dynamiquement des filtres et des rĂšgles d'agrĂ©gation. En fin de compte, tous les outils dĂ©cents gĂ©nĂšrent une requĂȘte SQL.
Dans cet exemple, nous allons crĂ©er des requĂȘtes SQL prĂȘtes Ă l'emploi et les enregistrer en tant que vue dans la base de donnĂ©es - ce sont les rapports.
Visualisation
Bluff: de beaux graphiques en JavaScript ont été utilisés comme outil de visualisation.
Pour cela, il a fallu utiliser PHP pour parcourir tous les rapports et générer un fichier html avec des tableaux.
$sqls = array( 'SELECT * FROM RPT_ACCESS_USER_VS_BOT', 'SELECT * FROM RPT_ACCESS_ANNOYING_BOT', 'SELECT * FROM RPT_ACCESS_TOP_HOUR_HIT', 'SELECT * FROM RPT_ACCESS_USER_ACTIVE', 'SELECT * FROM RPT_ACCESS_REQUEST_STATUS', 'SELECT * FROM RPT_ACCESS_TOP_REQUEST_PAGE', 'SELECT * FROM RPT_ACCESS_TOP_REQUEST_REFERRER', 'SELECT * FROM RPT_ACCESS_NEW_REQUEST', 'SELECT * FROM RPT_ACCESS_TOP_REQUEST_SUCCESS', 'SELECT * FROM RPT_ACCESS_TOP_REQUEST_ERROR' );
L'outil visualise simplement les tableaux de résultats.
Conclusion
En utilisant l'analyse Web comme exemple, l'article décrit les mécanismes nécessaires à la construction d'entrepÎts de données. Comme le montrent les résultats, les outils les plus simples sont suffisants pour une analyse approfondie et une visualisation des données.
Ă l'avenir, en utilisant l'exemple de ce stockage, nous essaierons de mettre en Ćuvre des structures telles que
les mesures à changement lent , les données de base, les niveaux d'agrégation et l'intégration de données provenant de différentes sources.
En outre, nous allons examiner de plus prĂšs l'
outil de gestion de processus ETL le plus simple basé sur une seule table.
Revenons au sujet de la mesure de la qualité des données et de l'automatisation de ce processus.
Nous Ă©tudierons les problĂšmes de l'environnement technique et de la maintenance des entrepĂŽts de donnĂ©es, pour lesquels nous mettons en Ćuvre un serveur de stockage avec des ressources minimales, par exemple, basĂ© sur le Raspberry Pi.