Estatísticas do sitio e o teu propio pequeno almacenamento

Webalizer e Google Analytics axudáronme a coñecer o que está a suceder nos sitios web durante moitos anos. Agora entendo que proporcionan moi pouca información útil. Ao ter acceso ao teu ficheiro access.log, é moi sinxelo comprender as estatísticas e implementar ferramentas bastante básicas, como sqlite, html, a linguaxe sql e calquera linguaxe de programación de scripts.

A fonte de datos para Webalizer é o ficheiro access.log do servidor. Así son as súas barras e números, dos que só se desprende o volume total de tráfico:

Estatísticas do sitio e o teu propio pequeno almacenamento
Estatísticas do sitio e o teu propio pequeno almacenamento
Ferramentas como Google Analytics recollen datos da propia páxina cargada. Amósanos un par de esquemas e liñas, en base ás que moitas veces é difícil sacar conclusións correctas. Quizais deberíase facer máis esforzo? Non sei.

Entón, que quería ver nas estatísticas de visitantes do sitio web?

Tráfico de usuarios e bots

Moitas veces o tráfico do sitio é limitado e é necesario ver canto tráfico útil se está a utilizar. Por exemplo, así:

Estatísticas do sitio e o teu propio pequeno almacenamento

Consulta de informe SQL

SELECT
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!='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 '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

O gráfico mostra a actividade constante dos bots. Sería interesante estudar en detalle os representantes máis activos.

Bots molestos

Clasificamos os bots en función da información do axente de usuario. As estatísticas adicionais sobre o tráfico diario, o número de solicitudes exitosas e non exitosas dan unha boa idea da actividade do bot.

Estatísticas do sitio e o teu propio pequeno almacenamento

Consulta de informe 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 != 'n.a.'
  AND datetime(FCT.EVENT_DT, 'unixepoch') >= date('now', '-14 day')
GROUP BY USG.USER_AGENT_NK
ORDER BY 3 DESC
LIMIT 10

Neste caso, o resultado da análise foi a decisión de restrinxir o acceso ao sitio engadíndoo ao ficheiro robots.txt

User-agent: AhrefsBot
Disallow: /
User-agent: dotbot
Disallow: /
User-agent: bingbot
Crawl-delay: 5

Os dous primeiros bots desapareceron da mesa e os robots MS baixaron das primeiras liñas.

Día e hora de maior actividade

Os repuntes son visibles no tráfico. Para estudalos en detalle, é necesario destacar a hora da súa aparición, e non é necesario mostrar todas as horas e días de medición do tempo. Isto facilitará atopar solicitudes individuais no ficheiro de rexistro se se precisa unha análise detallada.

Estatísticas do sitio e o teu propio pequeno almacenamento

Consulta de informe 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!='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

Observamos as horas máis activas 11, 14 e 20 do primeiro día no gráfico. Pero ao día seguinte ás 13:XNUMX os bots estaban activos.

Media da actividade diaria dos usuarios por semana

Resolvemos un pouco as cousas coa actividade e o tráfico. A seguinte pregunta foi a actividade dos propios usuarios. Para tales estatísticas, son desexables períodos de agregación longos, como unha semana.

Estatísticas do sitio e o teu propio pequeno almacenamento

Consulta de informe 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='n.a.' /* users only */
  AND HST.STATUS_GROUP IN ('Successful') /* good pages */
  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

As estatísticas semanais mostran que, de media, un usuario abre 1,6 páxinas ao día. O número de ficheiros solicitados por usuario neste caso depende da adición de novos ficheiros ao sitio.

Todas as solicitudes e os seus estados

Webalizer sempre mostraba códigos de páxina específicos e sempre quixen ver só o número de solicitudes e erros exitosos.

Estatísticas do sitio e o teu propio pequeno almacenamento

Consulta de informe 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

O informe mostra solicitudes, non clics (acertos), a diferenza de LINE_CNT, a métrica REQUEST_CNT calcúlase como COUNT(DISTINCT STG.REQUEST_NK). O obxectivo é mostrar eventos efectivos, por exemplo, os bots de MS enquisan o ficheiro robots.txt centos de veces ao día e, neste caso, tales enquisas contaranse unha vez. Isto permítelle suavizar os saltos no gráfico.

No gráfico podes ver moitos erros: son páxinas inexistentes. O resultado da análise foi a adición de redireccións desde páxinas remotas.

Peticións malas

Para examinar as solicitudes en detalle, pode mostrar estatísticas detalladas.

Estatísticas do sitio e o teu propio pequeno almacenamento

Consulta de informe 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

Esta lista tamén conterá todas as chamadas, por exemplo, unha solicitude a /wp-login.php Ao axustar as regras para reescribir as solicitudes do servidor, podes axustar a reacción do servidor ante tales solicitudes e envialas á páxina de inicio.

Entón, algúns informes sinxelos baseados no ficheiro de rexistro do servidor dan unha imaxe bastante completa do que está a suceder no sitio.

Como obter información?

Unha base de datos sqlite é suficiente. Imos crear táboas: auxiliar para o rexistro de procesos ETL.

Estatísticas do sitio e o teu propio pequeno almacenamento

Fase da táboa onde escribiremos ficheiros de rexistro usando PHP. Dúas táboas agregadas. Imos crear unha táboa diaria con estatísticas sobre axentes de usuarios e estados das solicitudes. Cada hora con estatísticas de solicitudes, grupos de estado e axentes. Catro táboas de medidas relevantes.

O resultado é o seguinte modelo relacional:

Modelo de datosEstatísticas do sitio e o teu propio pequeno almacenamento

Script para crear un obxecto nunha base de datos sqlite:

Creación de obxectos 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 '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);

Escenario

No caso do ficheiro access.log, é necesario ler, analizar e escribir todas as solicitudes na base de datos. Isto pódese facer directamente usando unha linguaxe de script ou usando ferramentas sqlite.

Formato do ficheiro de rexistro:

//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-]+) "(.*)" "(.*)"$/';

Propagación de claves

Cando os datos en bruto están na base de datos, cómpre escribir as claves que non están alí nas táboas de medición. Despois será posible construír unha referencia ás medidas. Por exemplo, na táboa DIM_REFERRER, a clave é unha combinación de tres campos.

Consulta de propagación de clave SQL

/* 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 propagación á táboa do axente de usuario pode conter lóxica de bot, por exemplo o fragmento 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 'n.a.' END AS AGENT_BOT

Táboas agregadas

Por último, cargaremos as táboas agregadas; por exemplo, a táboa diaria pódese cargar do seguinte xeito:

Consulta SQL para cargar agregado

/* 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

A base de datos sqlite permítelle escribir consultas complexas. CON contén a preparación de datos e claves. A consulta principal recolle todas as referencias ás dimensións.

A condición non permitirá cargar de novo o historial: CAST(STG.EVENT_DT AS INTEGER) > $param_epoch_from, onde o parámetro é o resultado da solicitude
'SELECT COALESCE(MAX(EVENT_DT), '3600') AS LAST_EVENT_EPOCH FROM FCT_ACCESS_USER_AGENT_DD'

A condición cargará só o día completo: CAST(STG.EVENT_DT AS INTEGER) < strftime('%s', date('agora', 'inicio do día'))

O reconto de páxinas ou arquivos realízase dun xeito primitivo, buscando un punto.

Informes

En sistemas de visualización complexos, é posible crear un metamodelo baseado en obxectos de base de datos, xestionar de forma dinámica filtros e regras de agregación. En definitiva, todas as ferramentas decentes xeran unha consulta SQL.

Neste exemplo, imos crear consultas SQL preparadas e gardalas como vistas na base de datos: estes son informes.

Visualización

Bluff: Utilizáronse gráficos fermosos en JavaScript como ferramenta de visualización

Para iso, foi necesario revisar todos os informes mediante PHP e xerar un ficheiro html con táboas.

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

A ferramenta simplemente visualiza táboas de resultados.

Saída

Usando a análise web como exemplo, o artigo describe os mecanismos necesarios para construír almacéns de datos. Como se desprende dos resultados, as ferramentas máis sinxelas son suficientes para a análise e visualización profunda dos datos.

No futuro, usando este repositorio como exemplo, tentaremos implementar estruturas como dimensións que cambian lentamente, metadatos, niveis de agregación e integración de datos de diferentes fontes.

Ademais, vexamos máis de cerca a ferramenta máis sinxela para xestionar procesos ETL baseados nunha única táboa.

Volvamos ao tema da medición da calidade dos datos e da automatización deste proceso.

Estudiaremos os problemas da contorna técnica e o mantemento dos almacenamentos de datos, para o que implantaremos un servidor de almacenamento con recursos mínimos, por exemplo, baseado nunha Raspberry Pi.

Fonte: www.habr.com

Engadir un comentario