4

Nginx+Lua实现访问日志收集系统

 2 years ago
source link: https://panda843.github.io/article/1758295789.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Nginx+Lua实现访问日志收集系统 | 是潘达呀

Nginx+Lua实现访问日志收集系统

发表于 2017-12-28 | 分类于 开发 | | 浏览4 次 | 字数统计: 1.4k | 阅读时长 ≈ 6

网站数据统计分析工具是网站站长和运营人员经常使用的一种工具,比较常用的有谷歌分析、百度统计和腾讯分析等等。所有这些统计分析工具的第一步都是网站访问数据的收集。目前主流的数据收集方式基本都是基于javascript的。

名称途径备注
访问时间web serverNginx $msec
IPweb serverNginx $remote_addr
域名javascriptdocument.domain
URLjavascriptdocument.URL
页面标题javascriptdocument.title
分辨率javascriptwindow.screen.height & width
颜色深度javascriptwindow.screen.colorDepth
Referrerjavascriptdocument.referrer
浏览客户端web serverNginx $http_user_agent
客户端语言javascriptnavigator.language
访客标识cookie
网站标识javascript自定义对象
# 埋点代码
<script type="text/javascript">  
var _maq = _maq || [];
_maq.push(['_setAccount', '网站标识']);

(function() {
var ma = document.createElement('script'); ma.type = 'text/javascript'; ma.async = true;
ma.src = ('https:' == document.location.protocol ? 'https://tj' : 'http://tj') + '.tongji.com/ma.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ma, s);
})();
</script>

前端统计脚本

(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://tj.tongji.com/1.gif?' + args;
})();

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

#日志采用每行一条记录的方式,采用不可见字符^A(ascii码0x01,Linux下可通过ctrl + v ctrl + a输入,下文均用“^A”表示不可见字符0x01),具体格式如下:
#时间^AIP^A域名^AURL^A页面标题^AReferrer^A分辨率高^A分辨率宽^A颜色深度^A语言^A客户端信息^A用户标识^A网站标识。
#注意这里以u_开头的是我们待会会自己定义的变量,其它的是nginx内置变量
log_format tick "$msec^A$remote_addr^A$u_domain^A$u_url^A$u_title^A$u_referrer^A$u_sh^A$u_sw^A$u_cd^A$u_lang^A$http_user_agent^A$u_utrace^A$u_account";

Nginx+Lua配置

nginx配置本身的逻辑表达能力有限,这里选用了OpenResty做这个事情。OpenResty是一个基于Nginx扩展出的高性能应用开发平台,内部集成了诸多有用的模块,其中的核心是通过ngx_lua模块集成了 Lua,从而在nginx配置文件中可以通过Lua来表述业务。这里用到了诸多第三方ngxin模块(全都包含在OpenResty中了)

location /1.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
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_utrace $arg_utrace;
set_unescape_uri $u_account $arg_account;

#打开日志
log_subrequest on;
#记录日志到ma.log,实际应用中最好加buffer,格式为tick
access_log /path/to/logs/directory/ma.log tick;

#输出空字符串
echo '';
}

真正的日志收集系统访问日志会非常多,时间一长文件变得很大,而且日志放在一个文件不便于管理。所以通常要按时间段将日志切分,例如每天或每小时切分一个日志。这里为了效果明显,每一小时切分一个日志。并通过crontab定时调用一个shell脚本实现

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

Contab配置

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

注意,原始日志最好尽量多的保留信息而不要做过多过滤和处理。例如上面的MyAnalytics保留了毫秒级时间戳而不是格式化后的时间,时间的格式化是后面的系统做的事而不是日志收集系统的责任。后面的系统根据原始日志可以分析出很多东西,例如通过IP库可以定位访问者的地域、user agent中可以得到访问者的操作系统、浏览器等信息,再结合复杂的分析模型,就可以做流量、来源、访客、地域、路径等分析了。当然,一般不会直接对原始日志分析,而是会将其清洗格式化后转存到其它地方,如MySQL或HBase中再做分析。

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK