網站日志流量分析系統之(日志埋點)


一、概述 

  日志埋點分為客戶端和服務器端。參考並轉自:https://www.cnblogs.com/hzhuxin/p/11152805.html,如有侵權,請聯系刪除。)

  ①客戶端埋點:支持 iOS、安卓、Web/H5、微信小程序,主要用於分析 UV、PV、點擊量等基本指標。例:下圖是Web端的埋點技術圖:

  

 

   ②服務器日志:采集后端業務服務器打印的日志。更強的采集能力,更好的支撐精細化分析場景。(這里可以參考大牛博客:https://www.cnblogs.com/hzhuxin/p/11152805.html

二、服務器規划

三、日志埋點實現

(1)客戶端埋點

    在本項目案例中,采用客戶端網頁埋點實現,在其中需要埋點的頁面中的<head></head>中加入如下代碼:(參考並轉自:https://www.cnblogs.com/hzhuxin/p/11152805.html,如有侵權,請聯系刪除。)

         <script src="tj.js"></script>   注:tj.js 就是需埋點的 js 文件

/**函數可對字符串進行編碼,這樣就可以在所有的計算機上讀取該字符串。*/
function ar_encode(str)
{
    //進行URL編碼
    return encodeURI(str);
}


/**屏幕分辨率*/
function ar_get_screen()
{
    var c = "";

    if (self.screen) {
        c = screen.width+"x"+screen.height;
    }

    return c;
}

/**顏色質量*/
function ar_get_color()
{
    var c = "";

    if (self.screen) {
        c = screen.colorDepth+"-bit";
    }

    return c;
}

/**返回當前的瀏覽器語言*/
function ar_get_language()
{
    var l = "";
    var n = navigator;

    if (n.language) {
        l = n.language.toLowerCase();
    }
    else
    if (n.browserLanguage) {
        l = n.browserLanguage.toLowerCase();
    }

    return l;
}

/**返回瀏覽器類型IE,Firefox*/
function ar_get_agent()
{
    var a = "";
    var n = navigator;

    if (n.userAgent) {
        a = n.userAgent;
    }

    return a;
}

/**方法可返回一個布爾值,該值指示瀏覽器是否支持並啟用了Java*/
function ar_get_jvm_enabled()
{
    var j = "";
    var n = navigator;

    j = n.javaEnabled() ? 1 : 0;

    return j;
}

/**返回瀏覽器是否支持(啟用)cookie */
function ar_get_cookie_enabled()
{
    var c = "";
    var n = navigator;
    c = n.cookieEnabled ? 1 : 0;

    return c;
}

/**檢測瀏覽器是否支持Flash或有Flash插件*/
function ar_get_flash_ver()
{
    var f="",n=navigator;

    if (n.plugins && n.plugins.length) {
        for (var ii=0;ii<n.plugins.length;ii++) {
            if (n.plugins[ii].name.indexOf('Shockwave Flash')!=-1) {
                f=n.plugins[ii].description.split('Shockwave Flash ')[1];
                break;
            }
        }
    }
    else
    if (window.ActiveXObject) {
        for (var ii=10;ii>=2;ii--) {
            try {
                var fl=eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash."+ii+"');");
                if (fl) {
                    f=ii + '.0';
                    break;
                }
            }
            catch(e) {}
        }
    }
    return f;
}


/**匹配頂級域名*/
function ar_c_ctry_top_domain(str)
{
    var pattern = "/^aero$|^cat$|^coop$|^int$|^museum$|^pro$|^travel$|^xxx$|^com$|^net$|^gov$|^org$|^mil$|^edu$|^biz$|^info$|^name$|^ac$|^mil$|^co$|^ed$|^gv$|^nt$|^bj$|^hz$|^sh$|^tj$|^cq$|^he$|^nm$|^ln$|^jl$|^hl$|^js$|^zj$|^ah$|^hb$|^hn$|^gd$|^gx$|^hi$|^sc$|^gz$|^yn$|^xz$|^sn$|^gs$|^qh$|^nx$|^xj$|^tw$|^hk$|^mo$|^fj$|^ha$|^jx$|^sd$|^sx$/i";

    if(str.match(pattern)){ return 1; }

    return 0;
}

/**處理域名地址*/
function ar_get_domain(host)
{
    //如果存在則截去域名開頭的 "www."
    var d=host.replace(/^www\./, "");

    //剩余部分按照"."進行split操作,獲取長度
    var ss=d.split(".");
    var l=ss.length;

    //如果長度為3,則為xxx.yyy.zz格式
    if(l == 3){
        //如果yyy為頂級域名,zz為次級域名,保留所有
        if(ar_c_ctry_top_domain(ss[1]) && ar_c_ctry_domain(ss[2])){
        }
        //否則只保留后兩節
        else{
            d = ss[1]+"."+ss[2];
        }
    }
    //如果長度大於3
    else if(l >= 3){

        //如果host本身是個ip地址,則直接返回該ip地址為完整域名
        var ip_pat = "^[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*$";
        if(host.match(ip_pat)){
            return d;
        }
        //如果host后兩節為頂級域名及次級域名,則保留后三節
        if(ar_c_ctry_top_domain(ss[l-2]) && ar_c_ctry_domain(ss[l-1])) {
            d = ss[l-3]+"."+ss[l-2]+"."+ss[l-1];
        }
        //否則保留后兩節
        else{
            d = ss[l-2]+"."+ss[l-1];
        }
    }

    return d;
}


/**返回cookie信息*/
function ar_get_cookie(name)
{
    //獲取所有cookie信息
    var co=document.cookie;

    //如果名字是個空 返回所有cookie信息
    if (name == "") {
        return co;
    }

    //名字不為空 則在所有的cookie中查找這個名字的cookie
    var mn=name+"=";
    var b,e;
    b=co.indexOf(mn);

    //沒有找到這個名字的cookie 則返回空
    if (b < 0) {
        return "";
    }

    //找到了這個名字的cookie 獲取cookie的值返回
    e=co.indexOf(";", b+name.length);
    if (e < 0) {
        return co.substring(b+name.length + 1);
    }
    else {
        return co.substring(b+name.length + 1, e);
    }
}

/**
 設置cookie信息
 操作符:
 0 表示不設置超時時間 cookie是一個會話級別的cookie  cookie信息保存在瀏覽器內存當中 瀏覽器關閉時cookie消失
 1 表示設置超時時間為10年以后 cookie會一直保存在瀏覽器的臨時文件夾里 直到超時時間到來 或用戶手動清空cookie為止
 2 表示設置超時時間為1個小時以后 cookie會一直保存在瀏覽器的臨時文件夾里 直到超時時間到來 或用戶手動清空cookie為止
 * */
function ar_set_cookie(name, val, cotp)
{
    var date=new Date;
    var year=date.getFullYear();
    var hour=date.getHours();

    var cookie="";

    if (cotp == 0) {
        cookie=name+"="+val+";";
    }
    else if (cotp == 1) {
        year=year+10;
        date.setYear(year);
        cookie=name+"="+val+";expires="+date.toGMTString()+";";
    }
    else if (cotp == 2) {
        hour=hour+1;
        date.setHours(hour);
        cookie=name+"="+val+";expires="+date.toGMTString()+";";
    }

    var d=ar_get_domain(document.domain);
    if(d != ""){
        cookie +="domain="+d+";";
    }
    cookie +="path="+"/;";

    document.cookie=cookie;
}



/**返回客戶端時間*/
function ar_get_stm()
{
    return new Date().getTime();
}


/**返回指定個數的隨機數字串*/
function ar_get_random(n) {
    var str = "";
    for (var i = 0; i < n; i ++) {
        str += String(parseInt(Math.random() * 10));
    }
    return str;
}

/* main function */
function ar_main() {

    //收集完日志 提交到的路徑
    var dest_path   = "http://127.0.0.1:8081/log?";
    var expire_time = 30 * 60 * 1000;//會話超時時長

    //處理uv
    //--獲取cookie ar_stat_uv的值
    var uv_str = ar_get_cookie("ar_stat_uv");
    var uv_id = "";
    //--如果cookie ar_stat_uv的值為空
    if (uv_str == ""){
        //--為這個新uv配置id,為一個長度20的隨機數字
        uv_id = ar_get_random(20);
        //--設置cookie ar_stat_uv 保存時間為10年
        ar_set_cookie("ar_stat_uv", uv_id, 1);
    }
    //--如果cookie ar_stat_uv的值不為空
    else{
        //--獲取uv_id
        uv_id  = uv_str;
    }

    //處理ss
    //--獲取cookie ar_stat_ss
    var ss_stat = ar_get_cookie("ar_stat_ss");
    var ss_id = "";  //sessin id
    var ss_count = 0;   //session有效期內訪問頁面的次數
    var ss_time = "";
    //--如果cookie中不存在ar_stat_ss 說明是一次新的會話
    if (ss_stat == ""){
        //--隨機生成長度為10的session id
        ss_id = ar_get_random(10);
        //--session有效期內頁面訪問次數為0
        ss_count = 0;
        //--當前事件
        ss_time = ar_get_stm()
    } else { //--如果cookie中存在ar_stat_ss
        //獲取ss相關信息
        var items = ss_stat.split("_");
        //--ss_id
        ss_id  = items[0];
        //--ss_count
        ss_count  = parseInt(items[1]);
        //--ss_stm
        ss_time = items[2];

        //如果當前時間-當前會話上一次訪問頁面的時間>30分鍾,雖然cookie還存在,但是其實已經超時了!仍然需要重新生成cookie
        if (ar_get_stm() - ss_time > expire_time) {
            //--重新生成會話id
            ss_id = ar_get_random(10);
            //--設置會話中的頁面訪問次數為0
            ss_count = 0;
            //--當前事件
            ss_time = ar_get_stm();
        }else{//--如果會話沒有超時
            //--會話id不變
            //--設置會話中的頁面方位次數+1
            ss_count = ss_count + 1;
            ss_time = ar_get_stm();
        }
    }
    //--重新拼接cookie ar_stat_ss的值
    value = ss_id+"_"+ss_count+"_"+ss_time;
    ar_set_cookie("ar_stat_ss", value, 0);

    //當前地址
    var url = document.URL;
    url = ar_encode(String(url));

    //當前資源名
    var urlname = document.URL.substring(document.URL.lastIndexOf("/")+1);
    urlname = ar_encode(String(urlname));

    //返回導航到當前網頁的超鏈接所在網頁的URL
    var ref = document.referrer;
    ref = ar_encode(String(ref));


    //網頁標題
    var title = document.title;
    title = ar_encode(String(title));

    //網頁字符集
    var charset = document.charset;
    charset = ar_encode(String(charset));

    //屏幕信息
    var screen = ar_get_screen();
    screen = ar_encode(String(screen));

    //顏色信息
    var color =ar_get_color();
    color =ar_encode(String(color));

    //語言信息
    var language = ar_get_language();
    language = ar_encode(String(language));

    //瀏覽器類型
    var agent =ar_get_agent();
    agent =ar_encode(String(agent));

    //瀏覽器是否支持並啟用了java
    var jvm_enabled =ar_get_jvm_enabled();
    jvm_enabled =ar_encode(String(jvm_enabled));

    //瀏覽器是否支持並啟用了cookie
    var cookie_enabled =ar_get_cookie_enabled();
    cookie_enabled =ar_encode(String(cookie_enabled));

    //瀏覽器flash版本
    var flash_ver = ar_get_flash_ver();
    flash_ver = ar_encode(String(flash_ver));


    //當前ss狀態 格式為"會話id_會話次數_當前時間"
    var stat_ss = ss_id+"_"+ss_count+"_"+ss_time;
    //拼接訪問地址 增加如上信息
    dest=dest_path+"url="+url+"&urlname="+urlname+"&title="+title+"&chset="+charset+"&scr="+screen+"&col="+color+"&lg="+language+"&je="+jvm_enabled+"&ce="+cookie_enabled+"&fv="+flash_ver+"&cnv="+String(Math.random())+"&ref="+ref+"&uagent="+agent+"&stat_uv="+uv_id+"&stat_ss="+stat_ss;


    //通過插入圖片訪問該地址
    document.getElementsByTagName("body")[0].innerHTML += "<img src=\""+dest+"\" border=\"0\" width=\"1\" height=\"1\" />";

}

window.onload = function(){
    //觸發main方法
    ar_main();
}

  說明:

    ①var dest_path   = "http://127.0.0.1:8081/log?";     此處要改成日志服務器的地址,並且  這個地址是能夠被訪問的,最后一個 "?“ 不要忘加,用來拼后續參數使用的。

    ②埋點的原理:js代碼會動態在頁面中創建一個寬和高都是1px的圖片,圖片的地址指向了1中定義的日志服務器中的圖片,

             document.getElementsByTagName("body")[0].innerHTML += "<img src=\""+dest+"\" border=\"0\" width=\"1\" height=\"1\" />";

 (2)服務器端開發(關鍵代碼)

package com.logs.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

/**
 * @ProjectName: logdemo
 * @Package: com.logs.controller
 * @ClassName: LogController
 * @Author: dong
 * @Description: ${description}
 * @Date: 2019/9/4 22:39
 * @Version: 1.0
 */
@Controller
public class LogController {
    private Logger logger = LoggerFactory.getLogger(LogController.class);
    @RequestMapping("/log")
    public void log(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        //1.獲取請求參數
        String qs = request.getQueryString();
        //2.對URL解碼
        String decode = URLDecoder.decode(qs, "utf-8");
        //3.轉換成需要處理的格式
        StringBuilder sb = new StringBuilder();
        String[] attrs = decode.split("&");
        for (String attr : attrs) {
            String[] kv = attr.split("=");
            String val = kv.length >= 2 ? kv[1] : "";
            sb.append(val+"|");
        }
        sb.append(request.getRemoteAddr());
        String logStr = sb.toString();
//        System.out.println(logStr);
        logger.info(logStr);
    }
}

四、總結  

  至此,已經完成了日志的埋點,以供后續日志收集:網站日志流量分析系統之(日志收集)本項目地址https://github.com/Simple-Coder/log-demo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM