网站流量日志数据分析系统---网站流量日志数据自定义采集

网站流量日志数据分析系统---网站流量日志数据自定义采集_第1张图片
  网站流量数据统计分析,可以帮助网站管理员、运营人员、推广人员等实时获取网站流量信息,并从流量来源、网站内容、网站访客特性等多方面提供网站分析的数据依据。从而帮助提高网站流量,提升网站用户体验,让访客更多的沉淀下来变成会员或客户,通过更少的投入获取最大化的收入。
  技术上可以合理修改网站结构及适度分配资源,构建后台服务器群组,比如
  a、辅助改进网络的拓扑设计,提高性能
  b、在有高度相关性的节点之间安排快速有效的访问路径
  c、帮助企业更好地设计网站主页和安排网页内容
  业务上
  a、帮助企业改善市场营销决策,如把广告放在适当的 Web 页面上。
  b、优化页面及业务流程设计,提高流量转化率。
  c、帮助企业更好地根据客户的兴趣来安排内容。
  d、帮助企业对客户群进行细分,针对不同客户制定个性化的促销策略等。
  终极目标是:
改善网站的运营,获取更高投资回报率(ROI)。也就是赚更多的钱。
  访问日志指用户访问网站时的所有访问、浏览、点击行为数据。比如点击了哪一个链接,打开了哪一个页面,采用了哪个搜索项、总体会话时间等。而所有这些信息都可通过网站日志保存下来。通过分析这些数据,可以获知许多对网站运营至关重要的信息。采集的数据越全面,分析就能越精准。
  日志的生成渠道分为以下两种:
  一是:web 服务器软件(httpd、nginx、tomcat)自带的日志记录功能,如 Nginx的 access.log 日志;
  二是:自定义采集用户行为数据,通过在页面嵌入自定义的 javascript 代码来获取用户的访问行为(比如鼠标悬停的位置,点击的页面组件等),然后通过 ajax请求到后台记录日志,这种方式所能采集的信息会更加全面。在实际操作中,有以下几个方面的数据可以自定义的采集:
  系统特征:比如所采用的操作系统、浏览器、域名和访问速度等。
  访问特征:包括停留时间、点击的 URL、所点击的“页面标签”及标签的属性等。
  来源特征:包括来访 URL,来访 IP 等。
  产品特征:包括所访问的产品编号、产品类别、产品颜色、产品价格、产品利润、产品数量和特价等级等。
  以电商某东为例,其自定义采集的数据日志格式如下:

GET /log.gif?t=item.010001&m=UA-J2011-1&pin=-&uid=1679790178&sid=1679790178|12&v=je=1$sc=24-bit$sr=1600x900$ul=zh-cn$cs=GBK$dt=【云南白药套装】云南白药 牙膏 1803 (留兰香型)【行情 报价 价 格 评测】 - 京 东$hn=item.jd.com$fl=16.0r0$os=win$br=chrome$bv=39.0.2171.95$wb=1437269412$xb=1449548587$yb=1456186252$zb=12$cb=4$usc=direct$ucp=-$umd=none$uct=-$ct=1456186505411$lt=0$tad=-$sku=1326523$cid1=1316$cid2=1384$cid3=1405$brand=20583$pinid=-&ref=&rm=1456186505411 HTTP/1.1
  1. 原理分析
      首先,用户的行为会触发浏览器对被统计页面的一个 http 请求,比如打开某网页。当网页被打开,页面中的埋点 javascript 代码会被执行。
    网站流量日志数据分析系统---网站流量日志数据自定义采集_第2张图片
      埋点是指:在网页中预先加入小段 javascript 代码,这个代码片段一般会动态创建一个 script 标签,并将 src 属性指向一个单独的 js 文件,此时这个单独的 js 文件(图中绿色节点)会被浏览器请求到并执行,这个 js 往往就是真正的数据收集脚本。
      数据收集完成后,js 会请求一个后端的数据收集脚本(图中的 backend),这个脚本一般是一个伪装成图片的动态脚本程序,js 会将收集到的数据通过http 参数的方式传递给后端脚本,后端脚本解析参数并按固定格式记录到访问日志,同时可能会在 http 响应中给客户端种植一些用于追踪的 cookie。
  2. 设计实现
      根据原理分析并结合 Google Analytics,想搭建一个自定义日志数据采集系统,要做以下几件事:
    网站流量日志数据分析系统---网站流量日志数据自定义采集_第3张图片
    2.1 确定收集信息
名称 途径 备注
访问时间 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

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

<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(ma, 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 新引入的。
  扩展知识:js 自调用匿名函数
  格式: (function(){})();
  第一对括号向脚本返回未命名的函数;后一对空括号立即执行返回的未命名函数,括号内为匿名函数的参数。
  自调用匿名函数的好处是,避免重名,自调用匿名函数只会在运行时执行一次,一般用于初始化。
2.3 前端数据收集脚本
  数据收集脚本(ma.js)被请求后会被执行,一般要做如下几件事:
  a. 通过浏览器内置javascript对象收集信息,如页面title(通过document.title)、referrer(上一跳 url,通过 document.referrer)、用户显示器分辨率(通过windows.screen)、cookie 信息(通过document.cookie)等等一些信息。
  b. 解析_maq 数组,收集配置信息。这里面可能会包括用户自定义的事件跟踪、业务数据(如电子商务网站的商品编号等)等。
  c. 将上面两步收集的数据按预定义格式解析并拼接(get 请求参数)。
  d. 请求一个后端脚本,将信息放在 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 是后端脚本。
2.4 后端脚本
  log.gif 是后端脚本,是一个伪装成 gif 图片的脚本。后端脚本一般需要完成以下几件事情:
  a、解析 http 请求参数得到信息。
  b、从 Web 服务器中获取一些客户端无法获取的信息,如访客 ip 等。
  c、将信息按格式写入 log。
  d、生成一副 1×1 的空 gif 图片作为响应内容并将响应头的 Content-type设为 image/gif。
  e、在响应头中通过 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, mustrevalidate";
	#返回一个 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 中了),重点都用注释标出来,可以不用完全理解每一行的意义,只要大约知道这个配置完成了我们提到的后端逻辑就可以了。
2.5 日志格式
  日志格式主要考虑日志分隔符,一般会有以下几种选择:
固定数量的字符、制表符分隔符、空格分隔符、其他一个或多个字符、特
定的开始和结束文本。
2.6 日志切分
  日志收集系统访问日志时间一长文件变得很大,而且日志放在一个文件不便于管理。通常要按时间段将日志切分,例如每天或每小时切分一个日志。通过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 分启动这个脚本进行日志轮转操作。

  1. 系统环境部署
      服务器中安装依赖
yum -y install gcc perl pcre-devel openssl openssl-devel

  上传 LuaJIT-2.0.4.tar.gz 并安装 LuaJIT

tar -zxvf LuaJIT-2.0.4.tar.gz -C /usr/local/src/
cd /usr/local/src/LuaJIT-2.0.4/
make && make install PREFIX=/usr/local/luajit

  设置 LuaJIT 环境变量

vi /etc/profile
export LUAJIT_LIB=/usr/local/luajit/lib
export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0
source /etc/profile

  创建 modules 文件夹,保存 nginx 依赖的模块

mkdir -p /usr/local/nginx/modules

  上传 nginx 依赖的模块

set-misc-nginx-module-0.29.tar.gz 
lua-nginx-module-0.10.0.tar.gz
ngx_devel_kit-0.2.19.tar.gz
echo-nginx-module-0.58.tar.gz

  将依赖的模块直接解压到 modules 目录

tar -zxvf lua-nginx-module-0.10.0.tar.gz -C /usr/local/nginx/modules/
tar -zxvf set-misc-nginx-module-0.29.tar.gz -C /usr/local/nginx/modules/
tar -zxvf ngx_devel_kit-0.2.19.tar.gz -C /usr/local/nginx/modules/
tar -zxvf echo-nginx-module-0.58.tar.gz -C /usr/local/nginx/modules/

  安装 openresty

tar -zxvf openresty-1.9.7.3.tar.gz -C /usr/local/src/
cd /usr/local/src/openresty-1.9.7.3/
./configure --prefix=/usr/local/openresty --with-luajit && make && make install

  安装 nginx

tar -zxvf nginx-1.8.1.tar.gz -C /usr/local/src/

  编译 nginx 并支持其他模块

cd /usr/local/src/nginx-1.8.1/
./configure --prefix=/usr/local/nginx \
 --with-ld-opt="-Wl,-rpath,/usr/local/luajit/lib" \
 --add-module=/usr/local/nginx/modules/ngx_devel_kit-0.2.19 \
 --add-module=/usr/local/nginx/modules/lua-nginx-module-0.10.0 \
 --add-module=/usr/local/nginx/modules/set-misc-nginx-module-0.29 \
 --add-module=/usr/local/nginx/modules/echo-nginx-module-0.58 
make -j2
make install

  备注:如果对 linux 相关操作不熟,请严格按照上述步骤搭建环境,切记心细,心细,再心细。

  1. 自定义采集数据实现(详细步骤可查看下一篇文章)
    4.1 方案一:基本功能实现
      a) 创建页面 index.html,添加埋点代码,放入 nginx 默认目录 nginx/html 下。
      b) 在默认目录 nginx/html 下添加一个数据采集脚本 ma.js。
      c) 修改 nginx 的配置文件,添加自定义相关业务逻辑。
      d) 启动 nginx
sbin/nginx -c conf/nginx.conf 

  e) 通过游览器访问 nginx
  f) 观察自定义日志采集文件是否有对应的内容输出

tail -f logs/user_defined.log

  此时还可以观察 nginx 默认的输出日志文件

tail -f logs/access.log

  停止 nginx:

sbin/nginx –s stop

4.2 方案二:页面点击事件
详情请看下一篇文章

你可能感兴趣的:(大数据相关)