开源网站流量统计系统Piwik源码分析——后台处理(二)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:   在第一篇文章中,重点介绍了脚本需要搜集的数据,而本篇主要介绍的是服务器端如何处理客户端发送过来的请求和参数。

一、设备信息检测


  通过分析User-Agent请求首部(如下图红线框出的部分),可以得到相关的设备信息。

5.jpg


 Piwik系统专门有一套代码用来分析代理信息,还独立了出来,叫做DeviceDetector。它有一个专门的demo页面,可以展示其功能,点进去后可以看到下图中的内容。


6.jpg


  它能检测出浏览器名称、浏览器的渲染引擎、浏览器的版本、设备品牌(例如HTC、Apple、HP等)、设备型号(例如iPad、Nexus 5、Galaxy S5等)、设备类别(例如desktop、smartphone、tablet等),这6类数据中的可供选择的关键字,可以参考“List of segments”或插件的“readme”。顺便说一下,Piwik还能获取到访客的定位信息,在“List of segments”中,列举出了城市、经纬度等信息,其原理暂时还没研究。

  Piwik为大部分设备信息的关键字配备了一个icon图标,所有的icon图标被放置在“plugins\Morpheus\icons”中,包括浏览器、设备、国旗、操作系统等,下图截取的是浏览器中的部分图标。


7.jpg


二、IP地址


  在Piwik系统的后台设置中,可以选择IP地址的获取方式(如下图所示)。在官方博客的一篇《Geo Locate your visitors》博文中提到,3.5版本后可以在系统中嵌入MaxMind公司提供的IP地理定位服务(GeoIP2)。


8.jpg


  下面是一张看官方的产品介绍表,从描述中可看出这是一项非常厉害的服务。不过需要注意的是,这是一项付费服务。

9.png


三、日志数据和归档数据


  在官方发布的说明文档《How Matomo (formerly Piwik) Works》中提到,在Piwik中有两种数据类型:日志数据和归档数据。日志数据(Log Data)是一种原始分析数据,从客户端发送过来的参数就是日志数据,刚刚设备检测到的信息也是日志数据,还有其它的一些日志数据的来源,暂时还没细究。由于日志数据非常巨大,因此不能直接生成最终用户可看的报告,得使用归档数据来生成报告。归档数据(Archive Data)是以日志数据为基础而构建出来的,它是一种被缓存并且可用于生成报告的聚合分析数据。

  日志数据会通过“core\Piwik\Tracker\Visit.php”中的方法保存到数据库中,其中核心的方法如下所示,注释中也强调了该方法中的内容是处理请求的主要逻辑。该方法涉及到了很多对象,以及对象的方法,错综复杂,我自己也没有研究透,只是利用PHPStorm编辑器自动索引,查找出了一些关联,具体细节还有待考证。




/**
 *  Main algorithm to handle the visit.
 *
 *  Once we have the visitor information, we have to determine if the visit is a new or a known visit.
 *
 * 1) When the last action was done more than 30min ago,
 *      or if the visitor is new, then this is a new visit.
 *
 * 2) If the last action is less than 30min ago, then the same visit is going on.
 *    Because the visit goes on, we can get the time spent during the last action.
 *
 * NB:
 *  - In the case of a new visit, then the time spent
 *    during the last action of the previous visit is unknown.
 *
 *    - In the case of a new visit but with a known visitor,
 *    we can set the 'returning visitor' flag.
 *
 * In all the cases we set a cookie to the visitor with the new information.
 */
public function handle() {
    foreach ($this->requestProcessors as $processor) {
        Common::printDebug("Executing " . get_class($processor) . "::manipulateRequest()...");
        $processor->manipulateRequest($this->request);
    }
    $this->visitProperties = new VisitProperties();
    foreach ($this->requestProcessors as $processor) {
        Common::printDebug("Executing " . get_class($processor) . "::processRequestParams()...");
        $abort = $processor->processRequestParams($this->visitProperties, $this->request);
        if ($abort) {
            Common::printDebug("-> aborting due to processRequestParams method");
            return;
        }
    }
    $isNewVisit = $this->request->getMetadata('CoreHome', 'isNewVisit');
    if (!$isNewVisit) {
        $isNewVisit = $this->triggerPredicateHookOnDimensions($this->getAllVisitDimensions() , 'shouldForceNewVisit');
        $this->request->setMetadata('CoreHome', 'isNewVisit', $isNewVisit);
    }
    foreach ($this->requestProcessors as $processor) {
        Common::printDebug("Executing " . get_class($processor) . "::afterRequestProcessed()...");
        $abort = $processor->afterRequestProcessed($this->visitProperties, $this->request);
        if ($abort) {
            Common::printDebug("-> aborting due to afterRequestProcessed method");
            return;
        }
    }
    $isNewVisit = $this->request->getMetadata('CoreHome', 'isNewVisit');
    // Known visit when:
    // ( - the visitor has the Piwik cookie with the idcookie ID used by Piwik to match the visitor
    //   OR
    //   - the visitor doesn't have the Piwik cookie but could be match using heuristics @see recognizeTheVisitor()
    // )
    // AND
    // - the last page view for this visitor was less than 30 minutes ago @see isLastActionInTheSameVisit()
    if (!$isNewVisit) {
        try {
            $this->handleExistingVisit($this->request->getMetadata('Goals', 'visitIsConverted'));
        }
        catch(VisitorNotFoundInDb $e) {
            $this->request->setMetadata('CoreHome', 'visitorNotFoundInDb', true); // TODO: perhaps we should just abort here?
        }
    }
    // New visit when:
    // - the visitor has the Piwik cookie but the last action was performed more than 30 min ago @see isLastActionInTheSameVisit()
    // - the visitor doesn't have the Piwik cookie, and couldn't be matched in @see recognizeTheVisitor()
    // - the visitor does have the Piwik cookie but the idcookie and idvisit found in the cookie didn't match to any existing visit in the DB
    if ($isNewVisit) {
        $this->handleNewVisit($this->request->getMetadata('Goals', 'visitIsConverted'));
    }
    // update the cookie with the new visit information
    $this->request->setThirdPartyCookie($this->request->getVisitorIdForThirdPartyCookie());
    foreach ($this->requestProcessors as $processor) {
        Common::printDebug("Executing " . get_class($processor) . "::recordLogs()...");
        $processor->recordLogs($this->visitProperties, $this->request);
    }
    $this->markArchivedReportsAsInvalidIfArchiveAlreadyFinished();
}


  最后了解一下Piwik的数据库设计,此处只分析与日志数据和归档数据有关的数据表。官方的说明文档曾介绍,日志数据有5张相关的数据表,我对于表的内在含义还比较模糊,因此下面所列的描述还不是很清晰。

(1)log_visit:每次访问都会生成一条访问者记录,表中的字段可参考“Visits”。

(2)log_action:网站上的访问和操作类型(例如特定URL、网页标题),可分析出访问者感兴趣的页面,表中的字段可参考“Action Types”。

(3)log_link_visit_action:访问者在浏览期间执行的操作,表中的字段可参考“Visit Actions”。

(4)log_conversion:访问期间发生的转化(与目标相符的操作),表中的字段可参考“Conversions”。

(5)log_conversion_item:与电子商务相关的信息,表中的字段可参考“Ecommerce items”。

  归档数据的表有两种前缀,分别是“archive_numeric_”和“archive_blob_”,表的字段可参考“Archive data”。通过对字段的观察可知,两种最大的不同就是value字段的数据类型。archive_numeric_* 表中的value能储存数值(数据类型是Double),而archive_blob_* 表中的value能储存出数字以外的其他任何数据(数据类型是Blob)。

  两种表都是动态生成的,因此前缀的后面都用“*”表示。生成规则可按年、月、周、天或自定义日期范围,不设置的话,默认是按月计算,例如archive_numeric_2018_09、archive_blob_2018_09。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
7天前
|
JavaScript PHP 数据安全/隐私保护
乞丐在线要饭系统PHP网站源码
在这个物欲横流、竞争激烈的时代,有时候我们真心觉得钱来得太不容易,甚至连最基本的生存都成了负担。于是,我们想出了一个特别“独特”的点子:用利息砸我,给我点施舍!
29 1
|
6月前
|
Web App开发 JavaScript 前端开发
分析网站架构:浏览器插件
分析网站架构:浏览器插件
|
小程序 JavaScript 数据可视化
一分钟搭建小程序管理后台,借助云开发CMS搭建可视化的数据管理网页平台
一分钟搭建小程序管理后台,借助云开发CMS搭建可视化的数据管理网页平台
839 0
|
数据库
Discuz如何开发移动端访客功能(2)
Discuz如何开发移动端访客功能
133 0
Discuz如何开发移动端访客功能(2)
|
JSON 前端开发 JavaScript
开源网站流量统计系统Piwik源码分析——参数统计(一)
 Piwik现已改名为Matomo,这是一套国外著名的开源网站统计系统,类似于百度统计、Google Analytics等系统。最大的区别就是可以看到其中的源码,这正合我意。因为我一直对统计的系统很好奇,很想知道里面的运行原理是怎么样的,碰巧了解到有这么一个系统,因此马上尝试了一下。国内关于该系统的相关资料比较匮乏,大多是分享怎么安装的,并没有找到有关源码分析的文章。下面先对其做个初步的分析,后面会越来越详细,本人目前的职位是前端,因此会先分析脚本代码,而后再分析后台代码。
开源网站流量统计系统Piwik源码分析——参数统计(一)
|
测试技术
实战 | 基于JMeter 完成典型电商场景(首页浏览)的性能压测
实战 | 基于JMeter 完成典型电商场景(首页浏览)的性能压测
|
缓存 监控 Java
借助友盟+U-APM实现移动APP启动慢解决实践
本APP为面向用户的一款LBS产品。用户反馈APP使用过程中存在启动慢等问题。本文主要针对该原生Android APP启动慢的问题进行分析及解决方案的介绍。
借助友盟+U-APM实现移动APP启动慢解决实践
婚恋源码中的动态评论功能,有必要做吗?
婚恋源码中的动态评论功能,有必要做吗?
|
监控 搜索推荐 SEO
网站维护利器:PageAdmin Cms日志功能使用说明
很多时候大型网站页面数很多,我们没有办法一个一个检测每个页面是否能正常访问,经常都是用户反馈了某个页面不能访问后,网站维护人员才去处理问题,如果处理不及时会导致潜在用户流失,如果正好属于有排名的优化页面,严重的就导致页面搜索引擎排名丢失。
419 0
网站维护利器:PageAdmin Cms日志功能使用说明