网站流量日志数据自定义采集实现

兮夜那么美 兮夜那么美     2022-10-03     129

关键词:

为什么要进行网站流量数据统计分析?

随着大数据时代的到来,各行各业产生的数据呈爆发式增长,大数据的技术从之前的“虚无”变成可能,数据产生的各种潜在价值慢慢的被人们挖掘出来利用在各行各业上。比如网站流量数据统计分析,可以帮助网站管理员、运营人员、推广人员等实时获取网站流量信息,并从流量来源、网站内容、网站访客特性等多方面提供网站分析的数据依据。从而帮助提高网站流量,提升网站用户体验,让访客更多的沉淀下来变成会员或客户,通过更少的投入获取最大化的收入。

网站流量日志数据采集原理分析

  首先,用户的行为会触发浏览器对被统计页面的一个 http 请求,比如打开某网页。当网页被打开,页面中的埋点 javascript 代码会被执行。

  埋点是指:在网页中预先加入小段 javascript 代码,这个代码片段一般会动态创建一个 script 标签,并将 src 属性指向一个单独的 js 文件,此时这个单独的 js 文件(图中绿色节点)会被浏览器请求到并执行,这个 js 往往就是真正的数据收集脚本。

  数据收集完成后,js 会请求一个后端的数据收集脚本(图中的 backend),这个脚本一般是一个伪装成图片的动态脚本程序,js 会将收集到的数据通过http 参数的方式传递给后端脚本,后端脚本解析参数并按固定格式记录到访问日志,同时可能会在 http 响应中给客户端种植一些用于追踪的 cookie。

设计实现

  根据原理分析并结合 Google Analytics,想搭建一个自定义日志数据采集系统,要做以下几件事:

 

确定收集信息

名称 途径 备注
访问时间 web server Nginx $msec
IP web server Nginx $remote_addr
域名 javascript document.domain
URL javascript document.URL
页面标题 javascript document.title
分辨率 javascript window.screen.height & width
颜色深度 javascript window.screen.colorDepth
Referrer javascript document.referrer
浏览客户端 web server Nginx $http_user_agent
客户端语言 javascript navigator.language
访客标识 cookie Nginx $http_cookie
网站标识 javascript 自定义对象
状态码 web server Nginx $status
发送内容量 web server Nginx $body_bytes_sent

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

确定埋点代码

埋点,是网站分析的一种常用的数据采集方法。核心就是在需要进行数据采集的关键点植入统计代码,进行数据的采集。比如以谷歌分析原型来说,需要在页面中插入一段它提供的 javascript 片段,这个片段往往被称为埋点代码。(以Google的埋点代码为例)

<script type="text/javascript">
var _maq = _maq || [];
_maq.push(['_setAccount', 'UA-XXXXX-X']);
(function() {
var ma = document.createElement('script'); ma.type =
'text/javascript'; ma.async = true;
ma.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ma.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore( m a, s);
})();
</script>

其中_maq 是全局数组,用于放置各种配置,其中每一条配置的格式为:

_maq.push(['Action', 'param1', 'param2', ...]);

_maq 的机制不是重点,重点是后面匿名函数的代码,这段代码的主要目的就是引入一个外部的 js 文件(ma.js),方式是通过 document.createElement 方法创建一个 script 并根据协议(http 或 https)将 src 指向对应的 ma.js,最后将这个元素插入页面的 dom 树上。

注意 ma.async = true 的意思是异步调用外部 js 文件,即不阻塞浏览器的解析,待外部 js 下载完成后异步执行。这个属性是 HTML5 新引入的。

前端数据收集脚本

数据收集脚本(ma.js)被请求后会被执行,一般要做如下几件事:

  1. 通过浏览器内置javascript对象收集信息,如页面title (通过document.title)、referrer(上一跳 url,通过 document.referrer)、用户显示器分辨率(通过windows.screen)、cookie 信息(通过 document.cookie)等等一些信息。

  2. 解析_maq 数组,收集配置信息。这里面可能会包括用户自定义的事件跟踪、业务数据(如电子商务网站的商品编号等)等。
  3. 将上面两步收集的数据按预定义格式解析并拼接(get 请求参数)。
  4. 请求一个后端脚本,将信息放在 http request 参数中携带给后端脚本。

这里唯一的问题是步骤 4,javascript 请求后端脚本常用的方法是 ajax,但是ajax 是不能跨域请求的。一种通用的方法是 js 脚本创建一个 Image 对象,将 Image对象的 src 属性指向后端脚本并携带参数,此时即实现了跨域请求后端。这也是后端脚本为什么通常伪装成 gif 文件的原因。

示例代码

(function () {
var params = {};
//Document 对象数据
if(document) {
params.domain = document.domain || ''; 
params.url = document.URL || ''; 
params.title = document.title || ''; 
params.referrer = document.referrer || ''; 
}
//Window 对象数据
if(window && window.screen) {
params.sh = window.screen.height || 0;
params.sw = window.screen.width || 0;
params.cd = window.screen.colorDepth || 0;
}
//navigator 对象数据
if(navigator) {
params.lang = navigator.language || ''; 
}
//解析_maq 配置
if(_maq) {
for(var i in _maq) {
switch(_maq[i][0]) {
case '_setAccount':
params.account = _maq[i][1];
break;
default:
break;
}
}
}
//拼接参数串
var args = ''; 
for(var i in params) {
if(args != '') {
args += '&';
}
args += i + '=' + encodeURIComponent(params[i]);
}
//通过 Image 对象请求后端脚本
var img = new Image(1, 1); 
img.src = ' http://xxx.xxxxx.xxxxx/log.gif? ' + args;
})();

整个脚本放在匿名函数里,确保不会污染全局环境。其中 log.gif 是后端脚本。

后端脚本

log.gif 是后端脚本,是一个伪装成 gif 图片的脚本。后端脚本一般需要完成以下几件事情:

  1. 解析 http 请求参数得到信息。
  2. 从 Web 服务器中获取一些客户端无法获取的信息,如访客 ip 等。
  3. 将信息按格式写入 log。
  4. 生成一副 1×1 的空 gif 图片作为响应内容并将响应头的 Content-type设为 image/gif。
  5. 在响应头中通过 Set-cookie 设置一些需要的 cookie 信息。

  之所以要设置 cookie 是因为如果要跟踪唯一访客,通常做法是如果在请求时发现客户端没有指定的跟踪 cookie,则根据规则生成一个全局唯一的 cookie 并种植给用户,否则 Set-cookie 中放置获取到的跟踪 cookie 以保持同一用户 cookie不变。这种做法虽然不是完美的(例如用户清掉 cookie 或更换浏览器会被认为是两个用户),但是目前被广泛使用的手段。

  我们使用 nginx 的 的 access_log  做日志收集,不过有个问题就是 nginx 配置本身的逻辑表达能力有限,所以选用 OpenResty 做这个事情。

  OpenResty 是一个基于 Nginx 扩展出的高性能应用开发平台,内部集成了诸多有用的模块,其中的核心是通过 ngx_lua 模块集成了 Lua,从而在 nginx 配置文件中可以通过 Lua 来表述业务。

  Lua 是一种轻量小巧的脚本语言,用标准 C 语言编写并以源代码形式开放,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

  首先,需要在 nginx 的配置文件中定义日志格式:

log_format tick
"$msec||$remote_addr||$status||$body_bytes_sent||$u_domain||$u_url|
|$u_title||$u_referrer||$u_sh||$u_sw||$u_cd||$u_lang||$http_user_ag
ent||$u_account";

注意这里以 u_开头的是我们待会会自己定义的变量,其它的是 nginx 内置变量。然后是核心的两个 location:

location / log.gif {
#伪装成 gif 文件
default_type image/gif;
#本身关闭 access_log,通过 subrequest 记录 log
access_log off;
access_by_lua "
-- 用户跟踪 cookie 名为__utrace
local uid = ngx.var.cookie___utrace
if not uid then
-- 如果没有则生成一个跟踪 cookie,算法为
md5(时间戳+IP+客户端信息)
uid = ngx.md5(ngx.now() ..
ngx.var.remote_addr .. ngx.var.http_user_agent)
end 
ngx.header['Set-Cookie'] = {'__utrace=' .. uid ..
'; path=/'}
if ngx.var.arg_domain then
-- 通过 subrequest 子请求 到/i-log 记录日志,
将参数和用户跟踪 cookie 带过去
ngx.location.capture('/i-log?' ..
ngx.var.args .. '&utrace=' .. uid)
end 
";
#此请求资源本地不缓存
add_header Expires "Fri, 01 Jan 1980 00:00:00 GMT";
add_header Pragma "no-cache";
add_header Cache-Control "no-cache, max-age=0, must-
revalidate";
#返回一个 1×1 的空 gif 图片
empty_gif;
}
location /i-log {
#内部 location,不允许外部直接访问
internal;
#设置变量,注意需要 unescape,来自 ngx_set_misc 模块
set_unescape_uri $u_domain $arg_domain;
set_unescape_uri $u_url $arg_url;
set_unescape_uri $u_title $arg_title;
set_unescape_uri $u_referrer $arg_referrer;
set_unescape_uri $u_sh $arg_sh;
set_unescape_uri $u_sw $arg_sw;
set_unescape_uri $u_cd $arg_cd;
set_unescape_uri $u_lang $arg_lang;
set_unescape_uri $u_account $arg_account;
#打开日志
log_subrequest on;
#记录日志到 ma.log 格式为 tick
access_log /path/to/logs/directory/ma.log tick;
#输出空字符串
echo '';
}

这段脚本用到了诸多第三方ngxin模块(全都包含在 OpenResty 中了),重点都用注释标出来,可以不用完全理解每一行的意义,只要大约知道这个配置完成了我们提到的后端逻辑就可以了。

  日志格式

日志格式主要考虑日志分隔符,一般会有以下几种选择:

固定数量的字符、制表符分隔符、空格分隔符、其他一个或多个字符、特定的开始和结束文本。

日志切分

日志收集系统访问日志时间一长文件变得很大,而且日志放在一个文件不便于管理。通常要按时间段将日志切分,例如每天或每小时切分一个日志。通过crontab 定时调用一个 shell 脚本实现,如下:

_prefix="/path/to/nginx"
time=`date +%Y%m%d%H`
mv ${_prefix}/logs/ma.log ${_prefix}/logs/ma/ma-${time}.log
kill -USR1 `cat ${_prefix}/logs/nginx.pid `

  这个脚本将 ma.log 移动到指定文件夹并重命名为 ma-{yyyymmddhh}.log,然后向 nginx 发送 USR1 信号令其重新打开日志文件。

  USR1 通常被用来告知应用程序重载配置文件, 向服务器发送一个 USR1 信号将导致以下步骤的发生:停止接受新的连接,等待当前连接停止,重新载入配置文件,重新打开日志文件,重启服务器,从而实现相对平滑的不关机的更改。

  cat ${_prefix}/logs/nginx.pid 取 nginx 的进程号

  然后再/etc/crontab 里加入一行:

  59 * * * * root /path/to/directory/rotatelog.sh

  在每个小时的 59 分启动这个脚本进行日志轮转操作。

如何用istio实现监控和日志采集

大家都知道istio可以帮助我们实现灰度发布、流量监控、流量治理等一些功能。每一个功能都帮助我们在不同场景中实现不同的业务。那我们Istio是如何帮助我们实现监控和日志采集的呢?这里我们依然以Bookinfo应用程序作为贯穿... 查看详情

「springcloud」(三十八)搭建elk日志采集与分析系统

...的日志数据同样是爆发式增长,我们需要通过消息队列做流量削峰处理,Logstash官方提供Redis、Kafka、RabbitMQ等输入插件。Redis虽然可以用作消息队列,但其各项功能显示不如单一实现的消息队列,所以通常情况下并不使用它的消... 查看详情

帝国cms的功能

...,灵活的标签+用户自定义标签,使之能实现各式各样的网站页面与风格;栏目无限级分类;前台全部静态:可随受强大的访问量;强大的信息采集功能;超强广告管理功能。帝国CMS是不同于以往的CMS系统,他可以直接在后台通... 查看详情

向系统日志写入自定义数据

实现效果:  知识运用:  EventLog类的Source属性和WriteEntry方法实现代码:privatevoidbutton1_Click(objectsender,EventArgse)EventLogeventlog=newEventLog();eventlog.Source="System";eventlog.WriteEntry(textBox1.Text);   查看详情

idou老师教你学istio25:如何用istio实现监控和日志采集

大家都知道istio可以帮助我们实现灰度发布、流量监控、流量治理等功能。每一个功能都帮助我们在不同场景中实现不同的业务。那Istio是如何帮助我们实现监控和日志采集的呢?这里我们依然以Bookinfo应用程序作为贯穿此任务的... 查看详情

idou老师教你学istio25:如何用istio实现监控和日志采集

大家都知道istio可以帮助我们实现灰度发布、流量监控、流量治理等功能。每一个功能都帮助我们在不同场景中实现不同的业务。那Istio是如何帮助我们实现监控和日志采集的呢?这里我们依然以Bookinfo应用程序作为贯穿此任务的... 查看详情

idou老师教你学istio:如何用istio实现监控和日志采集

大家都知道istio可以帮助我们实现灰度发布、流量监控、流量治理等功能。每一个功能都帮助我们在不同场景中实现不同的业务。那Istio是如何帮助我们实现监控和日志采集的呢?这里我们依然以Bookinfo应用程序作为贯穿此任务的... 查看详情

网络分流器|高速骨干网流量采集与分流实现

网络分流器|高速骨干网流量采集与分流实现方案1流量采集|网络分流器所谓流量采集,就是将网络流量通过物理层、数据链路层的信号解析和解帧,实现IP原始报文的获取。骨干网流量采集系统是一种对骨干网进行流量获取并... 查看详情

大数据flume自定义类型(代码片段)

...4测试1自定义Interceptor1.1案例需求使用Flume采集服务器本地日志,需要按照日志类型的不同,将不同种类的日志发往不同的分析系统。1.2需求分析:Interceptor和MultiplexingChannelSelector案例在实际的开发中,一台服务器产生的... 查看详情

网络分流器|高速骨干网流量采集与分流实现方案

网络分流器|高速骨干网流量采集与分流实现方案1流量采集|网络分流器所谓流量采集,就是将网络流量通过物理层、数据链路层的信号解析和解帧,实现IP原始报文的获取。骨干网流量采集系统是一种对骨干网进行流量获取并... 查看详情

hadoop之网站流量日志数据分析(代码片段)

网站流量日志数据分析系统点击流数据模型点击流是指用户在网站上持续访问的轨迹,按照时间来进行先后区分,基本上所有大型网站都有日志埋点。通过js的方式,可以获得用户在网站上所访问的内容,包括url... 查看详情

日志收集系统flume及其应用

...e是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统。Flume支持定制各类数据发送方,用于收集各类型数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方(可定制)的能力。一... 查看详情

八爪鱼采集器怎么设置展开全文

...鱼采集器的设置方法:1、首先打开八爪鱼采集器,点击网站简易采集模式下的立即使用图标,选取需要采集的数据源,点击自定义任务;2、更改任务名,将任务放置在合适的任务组当中,输入需要搜索的关键词,设置采集该网... 查看详情

使用aop以及自定义注解实现业务日志的收集(代码片段)

直接上代码自定义注解:MyLog@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceMyLogStringvalue()default"";//value值是说明,会被记录到数据库里面自定义日志的实体类SysLog@Da 查看详情

数据库日志采集系统方案设计

前言汽车之家几年前已实现了应用日志的采集,但是对数据库日志并没有实现集中采集, 排查定位数据库故障原因不便。2021年我们研发了数据库日志采集分析平台系统,实现了数据库主机系统日志,数据库错误日志,... 查看详情

springaop+自定义注解实现日志记录

SpringAOP+自定义注解实现日志记录 关于自定义注解基本介绍可参考以往博客:https://www.cnblogs.com/DFX339/p/11386722.html此文主要是讲述如何通过注解标识记录日志信息,一般我们的Service接口都需要记录入参信息,参数校验,方法执... 查看详情

springaop+自定义注解实现日志记录

SpringAOP+自定义注解实现日志记录 关于自定义注解基本介绍可参考以往博客:https://www.cnblogs.com/DFX339/p/11386722.html此文主要是讲述如何通过注解标识记录日志信息,一般我们的Service接口都需要记录入参信息,参数校验,方法执... 查看详情

网站流量日志分析(模块开发——数据预处理)

*clip.hdev:Orientationofclips-找出Clip与极轴的夹角*关闭窗体更新dev_update_window(‘off‘)*读取图像read_image(Clip,‘clip‘)*获取图像大小get_image_size(Clip,Width,Height)*关闭窗体dev_close_window()*打开窗体,大小为图像的1/4dev_open_window(0,0,W 查看详情