Weboldal statisztikák és saját kis tároló

A Webalizer és a Google Analytics segédeszközök évek óta segítenek abban, hogy képet kapjak arról, mi történik a weboldalakon. Ma már értem, hogy nagyon kevés hasznos információt nyújtanak. Az access.log fájlomhoz való hozzáféréssel a statisztikai elemzés nagyon egyszerű, és csupán alapvető eszközökre, például sqlite-ra, html-re, sql-re és bármilyen programozási nyelvre van szükség.

A Webalizer adatforrása az access.log fájl. a szerver. Így néznek ki az oszlopai és számai, amelyekből csupán az összes forgalom mennyisége érthető:

Weboldal statisztikák és saját kis tároló
Weboldal statisztikák és saját kis tároló
Az olyan eszközök, mint a Google Analytics, önállóan gyűjtik az adatokat a betöltött oldalról. Két diagramos és vonalábrát mutatnak, amely alapján gyakran nehéz helyes következtetéseket levonni. Talán több erőfeszítést kellett volna tennem? Nem tudom.

Nos, mit szerettem volna látni a weboldal látogatottsági statisztikáiban?

Felhasználói és botforgalom

Gyakran a weboldalak forgalma korlátozott, és fontos látni, hogy mennyi hasznos forgalmat használnak. Például így:

Weboldal statisztikák és saját kis tároló

SQL jelentés lekérdezés

SELECT
1 AS 'StackedArea: A felhasználók és botok által generált forgalom',
strftime('%d.%m', datetime(FCT.EVENT_DT, 'unixepoch')) AS 'Nap',
SUM(CASE WHEN USG.AGENT_BOT!='n.a.' THEN FCT.BYTES ELSE 0 END)/1000 AS 'Botok, KB',
SUM(CASE WHEN USG.AGENT_BOT='n.a.' THEN FCT.BYTES ELSE 0 END)/1000 AS 'Felhasználók, 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

A grafikonból folyamatos botaktivitás látható. Érdekes lenne részletesen megvizsgálni a legaktívabb képviselőket.

Zavaró botok

A botokat a felhasználói ügynök információja alapján osztályozzuk. A napi forgalom, a sikeres és a sikertelen kérések számának további statisztikája jó képet ad a botok aktivitásáról.

Weboldal statisztikák és saját kis tároló

SQL jelentés lekérdezés

SELECT 
1 AS 'Tábla: Zavaró Botok',
MAX(USG.AGENT_BOT) AS 'Bot',
ROUND(SUM(FCT.BYTES)/1000/14.0, 1) AS 'KB naponta',
ROUND(SUM(FCT.IP_CNT)/14.0, 1) AS 'IP naponta',
ROUND(SUM(CASE WHEN STS.STATUS_GROUP IN ('Client Error', 'Server Error') THEN FCT.REQUEST_CNT/14.0 ELSE 0 END), 1) AS 'Hiba kérések naponta',
ROUND(SUM(CASE WHEN STS.STATUS_GROUP IN ('Successful', 'Redirection') THEN FCT.REQUEST_CNT/14.0 ELSE 0 END), 1) AS 'Sikeres kérések naponta',
USG.USER_AGENT_NK AS 'Ügynök'
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 != 'n.a.'
  AND datetime(FCT.EVENT_DT, 'unixepoch') >= date('now', '-14 day')
GROUP BY USG.USER_AGENT_NK
ORDER BY 3 DESC
LIMIT 10

Ebben az esetben az elemzés eredménye az volt, hogy korlátozni kell a webhelyhez való hozzáférést a robots.txt fájlba való bejegyzéssel.

Felhasználói ügynök: AhrefsBot
Tiltás: /
Felhasználói ügynök: dotbot
Tiltás: /
Felhasználói ügynök: bingbot
Kúszási késleltetés: 5

Az első két bot eltűnt a táblázatból, míg a MS robotok a felső sorokból hátrébb kerültek.

A legnagyobb aktivitás napja és időpontja

A forgalomban emelkedések láthatók. A részletes vizsgálathoz szükséges kiemelni az azok előfordulásának időpontját, nem szükséges megjeleníteni az összes órát és napot az időmérés során. Így könnyebben megtalálhatók az egyes kérések a naplófájlban, ha részletes elemzés szükséges.

Weboldal statisztikák és saját kis tároló

SQL jelentés lekérdezés

SELECT
1 AS 'Sor: Felhasználók és botok találatainak napja és időpontja',
strftime('%d.%m-%H', datetime(EVENT_DT, 'unixepoch')) AS 'Dátum Idő',
HIB AS 'Botok, Találatok',
HIU AS 'Felhasználók, Találatok'
FROM (
	SELECT
	EVENT_DT,
	SUM(CASE WHEN AGENT_BOT!='n.a.' THEN LINE_CNT ELSE 0 END) AS HIB,
	SUM(CASE WHEN AGENT_BOT='n.a.' 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

A grafikonon a legaktívabb órák 11, 14 és 20 az első napon. Másnap 13 órakor a robotok aktívak voltak.

A felhasználók napi átlagos aktivitása hetente

Már kicsit jobban átlátjuk az aktivitást és a forgalmat. A következő kérdés a felhasználók aktivitása volt. Az ilyen statisztikához ajánlott hosszú aggregációs időszakok, például egy hét.

Weboldal statisztikák és saját kis tároló

SQL jelentés lekérdezés

SELECT
1 as 'Sor: Napi Felhasználói Aktivitás Hetente',
strftime('%W week', datetime(FCT.EVENT_DT, 'unixepoch')) AS 'Hét',
ROUND(1.0*SUM(FCT.PAGE_CNT)/SUM(FCT.IP_CNT),1) AS 'Oldalak IP-nként naponta',
ROUND(1.0*SUM(FCT.FILE_CNT)/SUM(FCT.IP_CNT),1) AS 'Fájlok IP-nként naponta'
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='n.a.' /* felhasználók csak */
  AND HST.STATUS_GROUP IN ('Successful') /* jó oldalak */
  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

A heti statisztika azt mutatja, hogy átlagosan egy felhasználó napi 1,6 oldalt nyit meg. Az egy felhasználóra jutó kért fájlok száma ebben az esetben a weboldalra feltöltött új fájlok számától függ.

Minden kérés és azok státusza

A Webalizer mindig megmutatta a konkrét oldalkódokat, és szerettem volna, ha csak a sikeres kérések és hibák számát látom.

Weboldal statisztikák és saját kis tároló

SQL jelentés lekérdezés

SELECT
1 as 'Sor: Minden kérelem státusza',
strftime('%d.%m', datetime(FCT.EVENT_DT, 'unixepoch')) AS 'Nap',
SUM(CASE WHEN STS.STATUS_GROUP='Sikeres' THEN FCT.REQUEST_CNT ELSE 0 END) AS 'Siker',
SUM(CASE WHEN STS.STATUS_GROUP='Átirányítás' THEN FCT.REQUEST_CNT ELSE 0 END) AS 'Átirányítás',
SUM(CASE WHEN STS.STATUS_GROUP='Kliens hiba' THEN FCT.REQUEST_CNT ELSE 0 END) AS 'Ügyfél hiba',
SUM(CASE WHEN STS.STATUS_GROUP='Szerver hiba' THEN FCT.REQUEST_CNT ELSE 0 END) AS 'Szerver hiba'
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

A jelentés a kéréseket tükrözi, nem a kattintásokat (látogatások), mivel a LINE_CNT metrikát a REQUEST_CNT COUNT(DISTINCT STG.REQUEST_NK) értéke számítja. A cél az, hogy hatékony eseményeket mutasson, például a MS botjai naponta többször is lekérdezik a robots.txt fájlt, és ebben az esetben ezek a lekérdezések egyszer fognak számítani. Ez lehetővé teszi a grafikonon a kiugrások simítását.

A grafikonból sok hibát láthatunk - ezek nem létező oldalak. Az elemzés eredményeként átirányításokat adtunk hozzá az eltávolított oldalakról.

Hibás kérések

A kérések részletes vizsgálatához részletes statisztikát lehet megjeleníteni.

Weboldal statisztikák és saját kis tároló

SQL jelentés lekérdezés

SELECT
  1 AS 'Táblázat: Legnagyobb hibás kérések',
  REQ.REQUEST_NK AS 'Kérelem',
  'Hiba' AS 'Kérelem státusza',
  ROUND(SUM(FCT.LINE_CNT) / 14.0, 1) AS 'Látogatások naponta',
  ROUND(SUM(FCT.IP_CNT) / 14.0, 1) AS 'IP-k naponta',
  ROUND(SUM(FCT.BYTES)/1000 / 14.0, 1) AS 'KB naponta'
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 ('Kliens hiba', 'Szerver hiba')
  AND datetime(FCT.EVENT_DT, 'unixepoch') >= date('now', '-14 day')
GROUP BY REQ.REQUEST_NK
ORDER BY 4 DESC
LIMIT 20

Ebben a listában minden hívás szerepelni fog, például a kérés a /wp-login.php, a kérések átírási szabályainak kiigazításával. szerverrel ki lehet igazítani a szerver válaszát az ilyen kérésekre, és átirányíthatjuk őket a kezdőoldalra.

Tehát néhány egyszerű jelentés a szerver naplófájlja alapján teljes képet ad arról, mi történik az oldalon.

Hogyan szerezhetünk információt?

Az sqlite adatbázisok elegendőek. Létrehozunk táblázatokat: egy segédtáblát az ETL folyamatok naplózásához.

Weboldal statisztikák és saját kis tároló

Staging táblázat, ahová a log fájlokat írjuk PHP eszközökkel. Két aggregáló táblázat. Létrehozunk egy napi táblázatot a felhasználói ügynökökről és a kérések státuszairól, valamint egy óránkénti táblázatot a kérésekről, a státusz csoportokról és az ügynökökről. Négy megfelelő dimenziós táblázatot.

Ennek eredményeként a következő relációs modell jött létre:

AdatmodellWeboldal statisztikák és saját kis tároló

Script az objektum létrehozásához az sqlite adatbázisban:

DDL objektum létrehozása

TÖRLÉS TÁBLÁZAT HA NINCS 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 'n.a.', AGENT_OS TEXT NOT NULL DEFAULT 'n.a.', AGENT_ENGINE TEXT NOT NULL DEFAULT 'n.a.', AGENT_DEVICE TEXT NOT NULL DEFAULT 'n.a.', AGENT_BOT TEXT NOT NULL DEFAULT 'n.a.', UPDATE_DT INTEGER NOT NULL DEFAULT 0, UNIQUE (USER_AGENT_NK) ); INSERT INTO DIM_USER_AGENT (DIM_USER_AGENT_ID) VALUES (-1);

Stádium

Az access.log fájl esetében olvasni, parse-elni és beírni kell az adatbázisba az összes lekérdezést. Ezt meg lehet tenni közvetlenül a szkriptnyelv eszközeivel, vagy sqlite eszközeivel.

A log fájl formátuma:

//67.221.59.195 - - [28/Dec/2012:01:47:47 +0100] "GET /files/default.css HTTP/1.1" 200 1512 "https://project.edu/" "Mozilla/4.0"
//host ident auth time method request_nk protocol status bytes ref browser
$log_pattern = '/^([^ ]+) ([^ ]+) ([^ ]+) ([[^]]+]) "(.*) (.*) (.*)" ([0-9-]+) ([0-9-]+) "(.*)" "(.*)"$/';

Kulcsok propagálása

Amikor a nyers adatok az adatbázisban vannak, be kell írni a dimenziós táblákba azokat a kulcsokat, amelyek ott nincsenek. Ekkor lehetséges a hivatkozás kialakítása a dimenziókra. Például a DIM_REFERRER táblában a kulcs a három mező kombinációja.

SQL lekérdezés a kulcsok propagálásához

/* Propagate the referrer from access log */
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) /* отрезаем sid - специфика цмс */
	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

A felhasználói ügynökök táblába való propagálás tartalmazhat botlogikát, például egy sql részlet:


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 'n.a.' END AS AGENT_BOT

Aggregáló táblák

Az utolsó lépésben az aggregáló táblákat töltjük be, például a napi táblát a következőképpen lehet betölteni:

SQL lekérdezés az aggregátum betöltéséhez

/* Load fact from access log */
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 /* load epoch date */
  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

Az sqlite adatbázis lehetővé teszi bonyolult lekérdezések írását. A WITH tartalmazza az adatok és kulcsok előkészítését. A fő lekérdezés összegyűjti az összes hivatkozást a dimenziókra.

A feltétel nem engedi újra betölteni a történetet: CAST(STG.EVENT_DT AS INTEGER) > $param_epoch_from, ahol a paraméter a lekérdezés eredménye
'SELECT COALESCE(MAX(EVENT_DT), '3600') AS LAST_EVENT_EPOCH FROM FCT_ACCESS_USER_AGENT_DD'

A feltétel csak teljes napot tölt be: CAST(STG.EVENT_DT AS INTEGER) < strftime('%s', date('now', 'start of day'))

Oldalak vagy fájlok számlálása primitív módon történik, pont keresésével.

Jelentések

Bonyolult vizualizációs rendszerekben lehetőség van meta-modell létrehozására az adatbázis-objektumok alapján, dinamikusan kezelni a szűrőket és az aggregálási szabályokat. Végső soron minden tisztességes eszköz SQL lekérdezéseket generál.

Ebben a példában előre elkészített SQL lekérdezéseket hozunk létre, és ezeket nézetek formájában elmentjük az adatbázisban - ez lesz a jelentések.

Vizualizáció.

A vizualizációs eszközként a Bluff-ot használtuk: Szép grafikonok JavaScriptben

Ehhez PHP segítségével végigmentünk az összes jelentésen, és generáltunk egy html fájlt táblázatokkal.

$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'
);

Ez az eszköz egyszerűen vizualizálja az eredmények táblázatait.

Következtetés

A webanalízis példáján a cikk leírja az adathalmozók felépítéséhez szükséges mechanizmusokat. A végeredmények alapján a mélyreható adatelemzéshez és vizualizációhoz elegendő a legegyszerűbb eszközök használata.

Továbbiakban, ezen tároló példáján megpróbáljuk megvalósítani az olyan struktúrákat, mint a lassan változó dimenziók, metaadatok, aggregációs szintek és az adatok integrálása különböző forrásokból.

Részletesebben megvizsgáljuk az ETL folyamatok kezelésére szolgáló legegyszerűbb eszközt egyetlen táblázat alapján.

Térjünk vissza az adatok minőségének mérésére és ennek a folyamatnak az automatizálására.

Megvizsgáljuk a technikai környezet és az adathalmozók karbantartásának problémáit, ezért egy minimális erőforrással rendelkező tárolószervert valósítunk meg, például Raspberry Pi-alapján.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster