站点统计数据和您自己的小存储空间

多年来,Webalizer 和 Google Analytics 帮助我深入了解网站上发生的事情。 现在我明白他们提供的有用信息很少。 通过访问 access.log 文件,可以很容易地理解统计数据并实现相当基本的工具,例如 sqlite、html、sql 语言和任何脚本编程语言。

Webalizer 的数据源是服务器的access.log 文件。 这是它的条形和数字的样子,从中只能清楚总流量:

站点统计数据和您自己的小存储空间
站点统计数据和您自己的小存储空间
Google Analytics 等工具会从加载的页面本身收集数据。 他们向我们展示了一些图表和线条,基于这些图表和线条通常很难得出正确的结论。 也许应该付出更多努力? 不知道。

那么,我想在网站访问者统计数据中看到什么?

用户和机器人流量

通常网站流量是有限的,有必要查看有多少有用流量被使用。 例如,像这样:

站点统计数据和您自己的小存储空间

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

该图显示了机器人的持续活动。 详细研究最活跃的代表会很有趣。

烦人的机器人

我们根据用户代理信息对机器人进行分类。 有关每日流量、成功和不成功请求数量的其他统计数据可以很好地了解机器人活动。

站点统计数据和您自己的小存储空间

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

在这种情况下,分析的结果是决定通过将其添加到 robots.txt 文件来限制对该网站的访问

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

最初的两台机器人从桌子上消失了,MS机器人从第一行向下移动。

最活跃的日期和时间

交通量明显上升。 要详细研究它们,需要突出显示它们发生的时间,而不必显示时间测量的所有小时和天数。 如果需要详细分析,这将使您更容易在日志文件中找到各个请求。

站点统计数据和您自己的小存储空间

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

我们在图表上观察到第一天最活跃的时间 11、14 和 20。 但第二天 13:XNUMX,机器人就活跃起来了。

每周平均每日用户活动

我们对活动和流量进行了一些整理。 下一个问题是用户本身的活动。 对于此类统计数据,需要较长的聚合周期(例如一周)。

站点统计数据和您自己的小存储空间

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

每周统计数据显示,平均一名用户每天打开 1,6 个页面。 在这种情况下,每个用户请求的文件数量取决于向站点添加的新文件。

所有请求及其状态

Webalizer 总是显示特定的页面代码,我总是想查看成功请求和错误的数量。

站点统计数据和您自己的小存储空间

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

该报告显示请求,而不是点击(点击),与 LINE_CNT 不同,REQUEST_CNT 指标的计算方式为 COUNT(DISTINCT STG.REQUEST_NK)。 目标是显示有效事件,例如,MS 机器人每天对 robots.txt 文件进行数百次轮询,在这种情况下,此类轮询将被计数一次。 这使您可以平滑图表中的跳跃。

从图中您可以看到许多错误 - 这些是不存在的页面。 分析的结果是添加了来自远程页面的重定向。

错误的请求

要详细检查请求,您可以显示详细的统计信息。

站点统计数据和您自己的小存储空间

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

该列表还将包含所有调用,例如对 /wp-login.php 的请求。通过调整服务器重写请求的规则,您可以调整服务器对此类请求的反应并将其发送到起始页。

因此,基于服务器日志文件的一些简单报告可以相当完整地了解站点上发生的情况。

如何获取信息?

sqlite 数据库就足够了。 让我们创建表:辅助记录 ETL 过程。

站点统计数据和您自己的小存储空间

我们将使用 PHP 写入日志文件的表阶段。 两个聚合表。 让我们创建一个每日表,其中包含有关用户代理和请求状态的统计信息。 每小时提供有关请求、状态组和代理的统计信息。 四个相关测量表。

结果是以下关系模型:

数据模型站点统计数据和您自己的小存储空间

在 sqlite 数据库中创建对象的脚本:

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

阶段

对于access.log 文件,需要读取、解析和写入对数据库的所有请求。 这可以直接使用脚本语言或使用 sqlite 工具来完成。

日志文件格式:

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

密钥传播

当原始数据在数据库中时,您需要将不存在的键写入测量表中。 然后就可以建立测量结果的参考。 例如,在 DIM_REFERRER 表中,键是三个字段的组合。

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

传播到用户代理表可能包含机器人逻辑,例如 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

聚合表

最后,我们将加载聚合表;例如,可以按如下方式加载每日表:

用于加载聚合的 SQL 查询

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

sqlite 数据库允许您编写复杂的查询。 WITH包含数据和密钥的准备。 主查询收集对维度的所有引用。

条件将不允许再次加载历史记录:CAST(STG.EVENT_DT AS INTEGER) > $param_epoch_from,其中参数是请求的结果
'从 FCT_ACCESS_USER_AGENT_DD 选择 COALESCE(MAX(EVENT_DT), '3600') 作为 LAST_EVENT_EPOCH'

该条件将仅加载全天: CAST(STG.EVENT_DT AS INTEGER) < strftime('%s', date('now', 'start of day'))

对页面或文件进行计数是通过搜索点以原始方式进行的。

报告

在复杂的可视化系统中,可以基于数据库对象创建元模型,动态管理过滤器和聚合规则。 最终,所有像样的工具都会生成 SQL 查询。

在此示例中,我们将创建现成的 SQL 查询并将它们保存为数据库中的视图 - 这些是报告。

可视化

Bluff:JavaScript 中的漂亮图形被用作可视化工具

为此,需要使用 PHP 浏览所有报告并生成带有表格的 html 文件。

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

该工具只是将结果表可视化。

结论

本文以Web分析为例,描述了构建数据仓库所需的机制。 从结果可以看出,最简单的工具足以对数据进行深度分析和可视化。

未来,我们将以此存储库为例,尝试实现缓慢变化的维度、元数据、聚合级别以及不同来源数据的集成等结构。

另外,让我们仔细看看基于单个表管理 ETL 流程的最简单工具。

让我们回到测量数据质量和自动化该过程的主题。

我们将研究数据存储的技术环境和维护问题,为此我们将实现一个资源最少的存储服务器,例如基于Raspberry Pi。

来源: habr.com

添加评论