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

优采云 发布时间: 2020-12-19 11:17

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

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

  随着大数据时代的到来,各行各业所生成的数据爆炸了。大数据技术已从以前的``虚无''变为可能,人们逐渐发现由数据产生的各种潜在价值。用于各行各业。例如,对网站流量数据的统计分析可以帮助网站管理员,操作员,发起人等获取实时网站流量信息,并从流量来源,网站内容等各个方面提供信息,以及网站访问者特征网站分析的数据基础。这将有助于增加网站的访问量并改善网站的用户体验,使更多的访客成为会员或客户,并以较少的投资获得最大的收益。

  网站交通记录数据采集原理分析

  首先,用户的行为将触发浏览器对正在计数的页面的http请求,例如打开某个网页。打开网页后,将执行页面中嵌入的javascript代码。

  

  埋点是指:在网页中预先添加一小段javascript代码。此代码段通常将动态创建脚本标签,并将src属性指向单独的js文件。此时,浏览器将请求并执行此单独的js文件(图中的绿色节点)。该js通常是真正的数据采集脚本。

  数据采集完成后,js将请求后端数据采集脚本(图中的后端)。该脚本通常是伪装成图片的动态脚本程序。 js将通过http参数传递采集的数据。对于后端脚本,后端脚本解析参数并以固定格式记录访问日志。同时,它可能会在http响应中为客户端植入一些跟踪cookie。

  设计与实现

  基于原理分析并结合Google Analytics(分析),如果您要构建自定义日志数据采集系统,则需要执行以下操作:

  

  确认采集信息

  

  确定掩埋点代码

  埋点是用于网站分析的常用data 采集方法。核心是在需要数据采集来执行数据采集的关键点植入统计代码。例如,在Google Analytics(分析)原型中,需要将其提供的javascript片段插入页面。该片段通常称为嵌入式代码。 (以Google的嵌入式代码为例)

  

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

})();

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

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

  _maq的机制不是焦点,而是焦点在于后面的匿名函数代码。该代码的主要目的是通过通过document.createElement方法创建脚本并遵循协议(http或https)将src指向相应的ma.js来引入外部js文件(ma.js),最后将其插入元素放入页面的dom树中。

  请注意,ma.async = true表示外部js文件是异步调用的,即,它不会阻止浏览器的解析,并且将在外部js下载完成后异步执行。此属性是HTML5中新引入的。

  前端数据采集脚本

  数据采集脚本(ma.js)将在请求后执行。通常,应执行以下操作:

  通过浏览器的内置javascript对象采集信息,例如页面标题(通过document.title),引荐来源网址(最后一个URL,通过document.referrer),用户显示分辨率(通过windows.screen),cookie信息(通过document.cookie)等。解析_maq数组并采集配置信息。这可能包括用户定义的事件跟踪,业务数据(例如电子商务网站产品编号等)。以上两个步骤中采集的数据将以预定义的格式进行解析和拼接(获取请求参数)。请求后端脚本,然后将http请求参数中的信息放入后端脚本。

  这里唯一的问题是第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图片。后端脚本通常需要完成以下操作:

  分析http请求参数以获取信息。获取客户端无法从Web服务器获取的某些信息,例如visitor ip。以日志格式写入信息。生成1×1的空白gif图像作为响应内容,并将响应头的Content-type设置为image / gif。通过响应标头中的Set-cookie设置一些必需的cookie信息。

  设置cookie的原因是因为如果您要跟踪唯一的访问者,通常的做法是根据规则生成一个全局唯一的cookie,如果发现客户端没有该cookie,则将其植入用户。在请求时指定跟踪cookie,否则Set-cookie放置获取的跟踪cookie以保持相同的用户cookie不变。尽管这种方法并不完美(例如,清除cookie或更改浏览器的用户将被视为两个用户),但目前已广泛使用。

  我们使用nginx的access_log进行日志采集,但是存在一个问题,即nginx配置本身具有有限的逻辑表达能力,因此我们选择OpenResty来实现。

  OpenResty是基于Nginx的高性能应用程序开发平台。它集成了许多有用的模块,其核心是通过ngx_lua模块将Lua集成在一起,因此Lua可用于在nginx配置文件中表达业务。

  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 / 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中),关键点带有注释。只要您在完成我们提到的End逻辑就可以了之后,就不需要完全了解每一行的含义。

  日志格式

  日志格式主要考虑日志分隔符,通常有以下选项:

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

  日志细分

  只要日志采集系统访问日志,文件就会变得很大,并且很难在一个文件中管理日志。通常有必要根据时间段拆分日志,例如每天或每小时一个日志。它是通过定期通过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,然后将USR1信号发送给nginx以重新打开日志文件。

  USR1通常用于通知应用程序重新加载配置文件。向服务器发送USR1信号将导致执行以下步骤:停止接受新连接,等待当前连接停止,重新加载配置文件,然后重新打开日志文件,重新启动服务器以实现相对平稳的更改而不关闭

  cat $ {_ prefix} /logs/nginx.pid接受nginx的进程号

  然后在/ etc / crontab中添加一行:

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

  每小时59分钟启动此脚本以执行日志轮换操作。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线