Verktyget Webalizer och Google Analytics har hjÀlpt mig i mÄnga Är att fÄ en uppfattning om vad som hÀnder pÄ webbplatser. Nu inser jag att de ger mycket lite anvÀndbar information. Med tillgÄng till min access.log-fil Àr det mycket enkelt att förstÄ statistiken, och för att genomföra detta behövs bara grundlÀggande verktyg som sqlite, html, sql-sprÄk och vilket skriptsprÄk som helst.
DatakÀllan för Webalizer Àr access.log-filen servern. SÄ hÀr ser dess kolumner och siffror ut, som bara ger en översikt över den totala trafiken:


SÄdana verktyg som Google Analytics samlar in data frÄn den laddade sidan pÄ egen hand. De visar oss nÄgra diagram och linjer, utifrÄn vilka det ofta Àr svÄrt att dra korrekta slutsatser. Kanske borde ytterligare insatser ha gjorts? Jag vet inte.
SÄ vad ville jag se i webbplatsens besöksstatistik?
AnvÀndartjÀnsternas och botternas trafik
Ofta har webbplatser trafikbegrÀnsningar och det Àr nödvÀndigt att se hur mycket anvÀndbar trafik som utnyttjas. Till exempel sÄ hÀr:

SQL-frÄgan för rapporten
SELECT
1 AS 'StackedArea: Trafik genererad av AnvÀndare och Bots',
strftime('%d.%m', datetime(FCT.EVENT_DT, 'unixepoch')) AS 'Dag',
SUM(CASE WHEN USG.AGENT_BOT != 'n.a.' THEN FCT.BYTES ELSE 0 END) / 1000 AS 'Bots, KB',
SUM(CASE WHEN USG.AGENT_BOT = 'n.a.' THEN FCT.BYTES ELSE 0 END) / 1000 AS 'AnvÀndare, 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_DTGrafen visar konstant aktivitet frÄn bots. Det skulle vara intressant att noggrant studera de mest aktiva representanterna.
PÄtrÀngande bots
Vi klassificerar bots baserat pÄ information frÄn anvÀndaragenten. Ytterligare statistik över daglig trafik, antal lyckade och misslyckade förfrÄgningar ger en bra kÀnsla för botarnas aktivitet.

SQL-frÄgan för rapporten
SELECT
1 AS 'Tabell: PÄtrÀngande Bots',
MAX(USG.AGENT_BOT) AS 'Bot',
ROUND(SUM(FCT.BYTES) / 1000 / 14.0, 1) AS 'KB per Dag',
ROUND(SUM(FCT.IP_CNT) / 14.0, 1) AS 'IPs per Dag',
ROUND(SUM(CASE WHEN STS.STATUS_GROUP IN ('Klientfel', 'Serverfel') THEN FCT.REQUEST_CNT / 14.0 ELSE 0 END), 1) AS 'Fel förfrÄgningar per Dag',
ROUND(SUM(CASE WHEN STS.STATUS_GROUP IN ('Lyckad', 'Omdirigering') THEN FCT.REQUEST_CNT / 14.0 ELSE 0 END), 1) AS 'Lyckade förfrÄgningar per Dag',
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 != 'n.a.'
AND datetime(FCT.EVENT_DT, 'unixepoch') >= date('now', '-14 day')
GROUP BY USG.USER_AGENT_NK
ORDER BY 3 DESC
LIMIT 10I detta fall resulterade analysen i ett beslut att begrÀnsa Ätkomsten till webbplatsen genom att lÀgga till det i filen robots.txt
AnvÀndaragent: AhrefsBot
Som inte tillÄts: /
AnvÀndaragent: dotbot
Som inte tillÄts: /
AnvÀndaragent: bingbot
KrÀv fördröjning: 5
De tvÄ första botarna försvann frÄn tabellen, medan MS-botarna flyttades nerÄt.
Tidpunkt för högst aktivitet
I trafiken syns toppar. För att detaljstudera dem Àr det nödvÀndigt att sÀrskilja tiden för deras uppkomst, samtidigt som det inte Àr nödvÀndigt att visa alla timmar och dagar för tidsmÀtningen. Det blir enklare att hitta specifika förfrÄgningar i loggfilen vid behov av detaljerad analys.

SQL-frÄgan för rapporten
SELECT
1 AS 'Rad: Dag och Timme för Besök frÄn AnvÀndare och Botar',
strftime('%d.%m-%H', datetime(EVENT_DT, 'unixepoch')) AS 'Datum Tid',
HIB AS 'Botar, Besök',
HIU AS 'AnvÀndare, Besök'
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_DTVi observerar de mest aktiva timmarna 11, 14 och 20 den första dagen pÄ grafen. NÀsta dag vid 13-tiden var botarna aktiva.
Genomsnittlig daglig aktivitet för anvÀndare per vecka
Vi har fÄtt grepp om aktiviteten och trafiken. NÀsta frÄga gÀllde aktivitet hos anvÀndarna sjÀlva. För sÄdan statistik Àr lÀngres perioder av aggregering önskvÀrda, exempelvis en vecka.

SQL-frÄgan för rapporten
SELECT
1 as 'Rad: Genomsnittlig Daglig AnvÀndaraktivitet per Vecka',
strftime('%W vecka', datetime(FCT.EVENT_DT, 'unixepoch')) AS 'Vecka',
ROUND(1.0*SUM(FCT.PAGE_CNT)/SUM(FCT.IP_CNT),1) AS 'Sidor per IP per Dag',
ROUND(1.0*SUM(FCT.FILE_CNT)/SUM(FCT.IP_CNT),1) AS 'Filer per IP per Dag'
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.' /* endast anvÀndare */
AND HST.STATUS_GROUP IN ('Successful') /* bra sidor */
AND datetime(FCT.EVENT_DT, 'unixepoch') > date('now', '-3 month')
GROUP BY strftime('%W vecka', datetime(FCT.EVENT_DT, 'unixepoch'))
ORDER BY FCT.EVENT_DTStatistik för veckan visar att i genomsnitt öppnar en anvÀndare 1,6 sidor per dag. Antalet begÀrda filer per anvÀndare beror i detta fall pÄ tillÀgg av nya filer pÄ webbplatsen.
Alla förfrÄgningar och deras statusar
Webalizer visade alltid specifika koder för sidor och det var alltid önskvÀrt att bara se mÀngden lyckade förfrÄgningar och fel.

SQL-frÄgan för rapporten
VĂLJ
1 som 'Rad: Alla förfrÄgningar efter status',
strftime('%d.%m', datetime(FCT.EVENT_DT, 'unixepoch')) SOM 'Dag',
SUM(CASE NĂR STS.STATUS_GROUP='FramgĂ„ngsrik' DĂ
FCT.REQUEST_CNT ANNARS 0 SLUT) SOM 'FramgÄng',
SUM(CASE NĂR STS.STATUS_GROUP='Omdirigering' DĂ
FCT.REQUEST_CNT ANNARS 0 SLUT) SOM 'Omdirigera',
SUM(CASE NĂR STS.STATUS_GROUP='Klientfel' DĂ
FCT.REQUEST_CNT ANNARS 0 SLUT) SOM 'Klientfel',
SUM(CASE NĂR STS.STATUS_GROUP='Serverfel' DĂ
FCT.REQUEST_CNT ANNARS 0 SLUT) SOM 'Serverfel'
FRĂ
N
FCT_ACCESS_USER_AGENT_DD FCT,
DIM_HTTP_STATUS STS
VARFĂR FCT.DIM_HTTP_STATUS_ID=STS.DIM_HTTP_STATUS_ID
OCH datetime(FCT.EVENT_DT, 'unixepoch') >= date('nu', '-14 dagar')
GRUPPERA EFTER strftime('%d.%m', datetime(FCT.EVENT_DT, 'unixepoch'))
ORDNA EFTER FCT.EVENT_DTRapporten visar förfrÄgningar, inte klick (trÀffar), till skillnad frÄn LINE_CNT mÀts REQUEST_CNT som COUNT(DISTINCT STG.REQUEST_NK). MÄlet Àr att visa effektiva hÀndelser, till exempel, MS-botar som flera gÄnger per dag frÄgar filen robots.txt och i det hÀr fallet kommer sÄdana frÄgor att rÀknas som en gÄng. Detta hjÀlper till att jÀmna ut toppar pÄ grafen.
FrĂ„n grafen kan man se mĂ„nga fel â det Ă€r icke-existerande sidor. Resultatet av analysen var att lĂ€gga till omdirigeringar frĂ„n borttagna sidor.
Felaktiga förfrÄgningar
För att noggrant granska förfrÄgningarna kan detaljerad statistik visas.

SQL-frÄgan för rapporten
VĂLJ
1 SOM 'Tabell: Topp-fel-förfrÄgningar',
REQ.REQUEST_NK SOM 'FörfrÄgan',
'Fel' SOM 'FörfrÄgningsstatus',
AVGĂR(SUM(FCT.LINE_CNT) / 14.0, 1) SOM 'TrĂ€ffar per dag',
AVGĂR(SUM(FCT.IP_CNT) / 14.0, 1) SOM 'IP-adresser per dag',
AVGĂR(SUM(FCT.BYTES)/1000 / 14.0, 1) SOM 'KB per dag'
FRĂ
N
FCT_ACCESS_REQUEST_REF_HH FCT,
DIM_REQUEST_V_ACT REQ
VARFĂR FCT.DIM_REQUEST_ID = REQ.DIM_REQUEST_ID
OCH FCT.STATUS_GROUP I ('Klientfel', 'Serverfel')
OCH datetime(FCT.EVENT_DT, 'unixepoch') >= date('nu', '-14 dagar')
GRUPPERA EFTER REQ.REQUEST_NK
ORDNA EFTER 4 DESC
BEGRĂNSA 20I den hĂ€r listan kommer ocksĂ„ alla samtal att finnas, till exempel, förfrĂ„gan till /wp-login.php Genom att justera reglerna för omskrivning av förfrĂ„gningar servern kan vi justera serverns respons pĂ„ sĂ„dana förfrĂ„gningar och skicka dem till startsidan.
SÄ, nÄgra enkla rapporter baserade pÄ serverloggfilen ger en tillrÀckligt fullstÀndig bild av vad som hÀnder pÄ webbplatsen.
Hur fÄr man information?
SQLite-databaser Àr helt tillrÀckliga. Vi skapar tabeller: en hjÀlptabell för loggning av ETL-processer.

Staging-tabell dÀr vi kommer att skriva loggfiler med hjÀlp av PHP. TvÄ aggregator-tabeller. Vi skapar en daglig tabell med statistik över anvÀndaragenter och förfrÄgningsstatusar. En timmevis med statistik över förfrÄgningar, statusgrupper och agenter. Fyra tabeller för de relevanta mÀtningarna.
Som ett resultat blev den följande relationella modellen:
Datamodell
Script för att skapa objekt i SQLite-databasen:
DDL skapa objekt
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 '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);Staging
För access.log-filen mÄste alla förfrÄgningar lÀsas, parsa och skrivas till databasen. Detta kan göras antingen direkt med skriptsprÄket eller med hjÀlp av sqlite.
Loggfilsformat:
//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-]+) "(.*)" "(.*)"$/';
NyckelpÄdragning
NÀr rÄdata finns i databasen mÄste nycklarna för dimensionerna, som inte finns dÀr, skrivas till tabellerna. DÄ blir det möjligt att bygga kopplingar till dimensionerna. Till exempel Àr nyckeln i tabellen DIM_REFERRER en kombination av tre fÀlt.
SQL-frÄga för nyckelpÄdragning
/* 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 NULLNyckelpÄdragning i tabellen för anvÀndaragenter kan innehÄlla bot-logik, till exempel en SQL-snutt:
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_BOTAggregattabeller
Sist men inte minst ska vi ladda aggregattabeller, till exempel kan den dagliga tabellen laddas pÄ följande sÀtt:
SQL-frÄga för laddning av aggregat
/* 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_IDSQLite-databasen tillÄter skrivning av komplexa frÄgor. WITH innehÄller förberedelse av data och nycklar. HuvudfrÄgan samlar alla kopplingar till dimensionerna.
Villkoret hindrar att historik laddas in igen: CAST(STG.EVENT_DT AS INTEGER) > $param_epoch_from, dÀr parametern Àr resultatet av frÄgan
âSELECT COALESCE(MAX(EVENT_DT), â3600â) AS LAST_EVENT_EPOCH FROM FCT_ACCESS_USER_AGENT_DDâ
Villkoret laddar endast hela dagar: CAST(STG.EVENT_DT AS INTEGER) < strftime(â%sâ, date(ânowâ, âstart of dayâ))
Antal sidor eller filer rÀknas pÄ ett primitivt sÀtt genom att söka efter punkter.
Rapporter
I komplexa visualiseringssystem finns möjlighet att skapa en metamodell baserad pÄ databasen, dynamiskt hantera filter och aggregeringsregler. I slutÀndan genererar alla seriösa verktyg SQL-frÄgor.
I detta exempel kommer vi att skapa fĂ€rdiga SQL-frĂ„gor och spara dem som vyer i databasen â det Ă€r rapporter.
Visualisering
För visualisering av verktyg anvÀndes Bluff: Beautiful graphs in JavaScript
För detta krÀvdes det att anvÀnda PHP för att gÄ igenom alla rapporter och generera en html-fil med tabeller.
$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'
);Verktyget visualiserar helt enkelt resultatens tabeller.
Utdata
I exemplet med webbanalys beskriver artikeln de mekanismer som behövs för att bygga datalager. Som resultaten visar, rÀcker de enklaste verktygen för djup analys och visualisering av data.
I framtiden, med hjÀlp av detta datalager, kommer vi att försöka implementera strukturer som lÄngsam förÀndring av dimensioner, metadata, aggregeringsnivÄer och dataintegration frÄn olika kÀllor.
Vi kommer ocksÄ att titta pÄ det enklaste verktyget för att hantera ETL-processer baserat pÄ en enda tabell.
LÄt oss ÄtervÀnda till temat om mÀtning av datakvalitet och automatiseringen av denna process.
Vi kommer att studera problemen med den tekniska miljön och underhÄllet av datalager, för vilket vi implementerar en lagringsserver med minimala resurser, exempelvis baserat pÄ Raspberry Pi.
KĂ€lla: habr.com
