頁面埋點&nginx日誌採集
頁面(web容器:httpd/nginx負載均衡 + apache server)<===> 日誌採集服務器(nginx服務器)javascript
- 經過某個頁面跳轉到咱們的頁面;
- 咱們頁面一渲染完成加載埋點的js,執行業務邏輯採集信息;
- 採集頁面完成以後,訪問log.gif,把參數拼接在args發送給採集服務器;
- 採集服務器返回一個1*1空的圖片,斷開鏈接。
採集頁面埋點(在頁面body最後埋js)java
<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 = 'http://xxxxxx/ma.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ma, s); })(); </script>
採集服務器ma.jsnginx
(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://xxxxxx/log.gif?' + args; })();
日誌格式
日誌採用每行一條記錄的方式,採用不可見字符^A(ascii碼0×01,Linux下可經過ctrl + v ctrl + a輸入,下文均用「^A」表示不可見字符0×01),具體格式以下:git
時間^AIP^A域名^AURL^A頁面標題^AReferrer^A分辨率高^A分辨率寬^A顏色深度^A語言^A客戶端信息^A用戶標識^A網站標識github
後端腳本
爲了簡單和效率考慮,我打算直接使用nginx的access_log作日誌收集,不過有個問題就是nginx配置自己的邏輯表達能力有限,因此我選用了OpenResty作這個事情。OpenResty是一個基於Nginx擴展出的高性能應用開發平臺,內部集成了諸多有用的模塊,其中的核心是經過ngx_lua模塊集成了Lua,從而在nginx配置文件中能夠經過Lua來表述業務。關於這個平臺我這裏不作過多介紹,感興趣的同窗能夠參考其官方網站http://openresty.org/,或者這裏有其做者章亦春(agentzh)作的一個很是有愛的介紹OpenResty的slide:http://agentzh.org/misc/slides/ngx-openresty-ecosystem/,關於ngx_lua能夠參考:https://github.com/chaoslawful/lua-nginx-module。web
若傳統的啓動nginx出現以下異常錯誤: unknown directive "access_by_lua"算法
之因此報錯是缺乏nginx的三方插件 apache
安裝一個ngx_openresty 該集成包中有:Nginx,Lua或Luajit,ngx_lua,以及一些有用的Nginx第三方模塊。json
安裝步驟以下:後端
# 下載 wget https://openresty.org/download/openresty-1.13.6.2.tar.gz # 解壓 tar -zxf openresty-1.13.6.2.tar.gz # 安裝 cd openresty-1.13.6.1 ./configure --with-luajit make make install #安裝完成默認路徑 cd /usr/local/openresty # 配置nginx服務器
首先,須要在nginx的配置文件中定義日誌格式:
log_format tick escape=json "$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";
注意這裏以u_開頭的是咱們待會會本身定義的變量,其它的是nginx內置變量。
採集服務器nginx配置
在nginx 1.11.8
以上版本中log_format
增長了escape=json
參數,在配置日誌格式時加上轉義中文。
worker_processes 2; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; log_format tick escape=json "$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"; access_log logs/access.log tick; sendfile on; keepalive_timeout 65; server { listen 80; server_name localhost; 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 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 這個地方的nginx_logs文件夾 須要先建立好 mkdir /usr/local/openresty/nginx/nginx_logs access_log nginx_logs/ma.log tick; #輸出空字符串 echo ''; } } }
要徹底解釋這段腳本的每個細節有點超出本文的範圍,並且用到了諸多第三方ngxin模塊(全都包含在OpenResty中了),重點的地方我都用註釋標出來了,能夠不用徹底理解每一行的意義,只要大約知道這個配置完成了咱們在原理一節提到的後端邏輯就能夠了。
測試
點擊跳轉須要埋點的頁面
埋點的頁面
埋點的頁面 ,能夠看到已經請求了 http://xxx/log.gif 了
已經寫入日誌了。成功