gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長(zhǎng)資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

初探埋點(diǎn)系統(tǒng)

初探埋點(diǎn)系統(tǒng)

相關(guān)學(xué)習(xí)推薦:javascript視頻教程

前言

最近雜七雜八的事情比較多,難得抽出時(shí)間來(lái)彌補(bǔ)一下之前的系列,欠大家的埋點(diǎn)系列現(xiàn)在開(kāi)始走起來(lái)

為什么需要埋點(diǎn)系統(tǒng)

電影中

前端開(kāi)發(fā)攻城獅開(kāi)開(kāi)心心的 coding,非常自豪的進(jìn)行了業(yè)務(wù)、UI 分離開(kāi)發(fā),各種設(shè)計(jì)模式、算法優(yōu)化輪番上陣,代碼寫(xiě)的 Perfect(勞資代碼天下第一),沒(méi)有 BUG,程序完美,兼容性 No.1,代碼能打能抗質(zhì)量高。下班輕松打卡,回家看娃。

現(xiàn)實(shí)中

實(shí)際上,開(kāi)發(fā)環(huán)境與生產(chǎn)環(huán)境并不能等同,并且測(cè)試的過(guò)程再完善,依然會(huì)有漏測(cè)的情況存在。考慮到用戶使用客戶端環(huán)境、網(wǎng)絡(luò)環(huán)境等等一系列的不確定因素存在。

所以在開(kāi)發(fā)過(guò)程中一定要記得三大原則(我胡謅的

  1. 沒(méi)有完美的代碼,只有沒(méi)發(fā)現(xiàn)的 BUG
  2. 絕對(duì)不要相信測(cè)試環(huán)境,沒(méi)有一種測(cè)試環(huán)境都涵蓋所有線上情況
  3. 如果線上沒(méi)有一點(diǎn)反饋,不要懷疑,問(wèn)題應(yīng)該藏得很深、很深

什么是埋點(diǎn)系統(tǒng)

埋點(diǎn)就像城市中的攝像頭,從產(chǎn)品的角度考慮,它可以監(jiān)控到用戶在我們產(chǎn)品里的行為軌跡,為產(chǎn)品的迭代、項(xiàng)目的穩(wěn)定提供依據(jù),WHO、WHEN、WHERE、HOW、WHAT 是埋點(diǎn)采集數(shù)據(jù)的基礎(chǔ)維度

對(duì)前端開(kāi)發(fā)而言,可以監(jiān)控頁(yè)面資源加載性能,異常等等,提供了頁(yè)面體驗(yàn)和健康指數(shù),為后續(xù)性能優(yōu)化提供依據(jù),及時(shí)上報(bào)異常和發(fā)生場(chǎng)景。從而能夠及時(shí)修正問(wèn)題,提高項(xiàng)目質(zhì)量等。

埋點(diǎn)可以大概分為三類:

  1. 無(wú)痕埋點(diǎn) – 無(wú)差別收集頁(yè)面所有信息包括頁(yè)面進(jìn)出、事件點(diǎn)擊等等,需要進(jìn)行數(shù)據(jù)沖洗才能獲取到有用信息
  2. 可視化埋點(diǎn) – 根據(jù)生成的頁(yè)面結(jié)構(gòu)獲取特定點(diǎn)位,單獨(dú)埋點(diǎn)分析
  3. 業(yè)務(wù)代碼手動(dòng)埋點(diǎn) – 根據(jù)具體復(fù)雜的業(yè)務(wù),除掉上述兩種不能涵蓋的地方進(jìn)行業(yè)務(wù)代碼埋點(diǎn)
代碼埋點(diǎn) 可視化埋點(diǎn) 無(wú)痕埋點(diǎn)
典型場(chǎng)景 無(wú)痕埋點(diǎn)無(wú)法覆蓋到,比如需要業(yè)務(wù)數(shù)據(jù) 簡(jiǎn)單規(guī)范的頁(yè)面場(chǎng)景 簡(jiǎn)單規(guī)范的頁(yè)面場(chǎng)景,
優(yōu)勢(shì) 業(yè)務(wù)數(shù)據(jù)明確 開(kāi)發(fā)成本低,運(yùn)營(yíng)人員可直接進(jìn)行相關(guān)埋點(diǎn)配置 無(wú)需配置,數(shù)據(jù)可回溯
不足 數(shù)據(jù)不可回溯,開(kāi)發(fā)成本高 不能關(guān)聯(lián)業(yè)務(wù)數(shù)據(jù),數(shù)據(jù)不可回溯 數(shù)據(jù)量較大,不能關(guān)聯(lián)業(yè)務(wù)數(shù)據(jù)

大部分情況,我們可以通過(guò)無(wú)痕埋點(diǎn)收集到所有的信息數(shù)據(jù),再配合可視化埋點(diǎn),能夠具體定位到某一個(gè)點(diǎn)位,這樣大部分的埋點(diǎn)信息都據(jù)此分析出來(lái)。

在特殊情況下,可以多加上業(yè)務(wù)代碼手動(dòng)埋點(diǎn),處理一下特別的場(chǎng)景(大部分情況是走強(qiáng)業(yè)務(wù)與正常的點(diǎn)擊,刷新事件無(wú)關(guān)需要上報(bào)的信息)

埋點(diǎn) SDK 開(kāi)發(fā)

埋點(diǎn)數(shù)據(jù)收集分析

  • 事件基本數(shù)據(jù)
    • 事件發(fā)生時(shí)間
    • 發(fā)生時(shí)頁(yè)面信息快照
  • 頁(yè)面
    • 頁(yè)面 PV,UV
    • 用戶頁(yè)面停留時(shí)長(zhǎng)
    • 頁(yè)面跳轉(zhuǎn)事件
    • 頁(yè)面進(jìn)入后臺(tái)
    • 用戶離開(kāi)頁(yè)面
  • 用戶信息
    • 用戶 uid
    • 用戶設(shè)備指紋
    • 設(shè)備信息
    • ip
    • 定位
  • 用戶操作行為
    • 用戶點(diǎn)擊
      • 點(diǎn)擊目標(biāo)
  • 頁(yè)面 AJAX 請(qǐng)求
    • 請(qǐng)求成功
    • 請(qǐng)求失敗
    • 請(qǐng)求超時(shí)
  • 頁(yè)面報(bào)錯(cuò)
    • 資源加載報(bào)錯(cuò)
    • JS 運(yùn)行報(bào)錯(cuò)
  • 資源加載新性能
  • 圖片
  • 腳本
  • 頁(yè)面加載性能

上面的數(shù)據(jù)通過(guò) 3 個(gè)維度來(lái)定義埋點(diǎn)事件

  • ·LEVEL: 描述埋點(diǎn)數(shù)據(jù)的日志級(jí)別
    • INFO:一些用戶操作,請(qǐng)求成功,資源加載等等正常的數(shù)據(jù)記錄
    • ERROR: JS報(bào)錯(cuò),接口報(bào)錯(cuò)等等錯(cuò)誤類型的數(shù)據(jù)記錄
    • DEBUG: 預(yù)留開(kāi)發(fā)人員通過(guò)手動(dòng)調(diào)用的方式回傳排除bug的數(shù)據(jù)記錄
    • WARN: 預(yù)留開(kāi)發(fā)人員通過(guò)手動(dòng)調(diào)用的方式回傳非正常用戶行為的的數(shù)據(jù)記錄
  • CATEGORY:描述埋點(diǎn)數(shù)據(jù)的分類
    • TRACK: 埋點(diǎn)SDK對(duì)象的生命周期管理整個(gè)埋點(diǎn)數(shù)據(jù)。
      • WILL_MOUNT:sdk對(duì)象即將初始化加載,生成一個(gè)默認(rèn)ID,跟蹤全部相關(guān)事件
      • DID_MOUNTED:sdk對(duì)象初始化完成,主要獲取設(shè)備指紋等等的異步操作完成
    • AJAX: AJAX相關(guān)數(shù)據(jù)
    • ERROR:頁(yè)面中的異常相關(guān)數(shù)據(jù)
    • PERFORMANCE: 關(guān)于性能相關(guān)數(shù)據(jù)
    • OPERATION: 用戶操作相關(guān)數(shù)據(jù)
  • EVENT_NAME:具體的事件名稱

根據(jù)上述的維度,我們可以簡(jiǎn)單設(shè)計(jì)如下的架構(gòu)

初探埋點(diǎn)系統(tǒng)

根據(jù)上圖的架構(gòu),再進(jìn)行下面的具體代碼開(kāi)發(fā)

代理請(qǐng)求

在瀏覽器中現(xiàn)在主要有 2 種請(qǐng)求方式,一個(gè)是 XMLHttpRequest, 一個(gè)是 Fetch

代理 XMLHttpRequest

function NewXHR() {  var realXHR: any = new OldXHR(); // 代理模式里面有提到過(guò)   realXHR.id = guid()  const oldSend = realXHR.send;    realXHR.send = function (body) {     oldSend.call(this, body)    //記錄埋點(diǎn)   }   realXHR.addEventListener('load', function () {    //記錄埋點(diǎn)   }, false);   realXHR.addEventListener('abort', function () {    //記錄埋點(diǎn)   }, false);    realXHR.addEventListener('error', function () {    //記錄埋點(diǎn)   }, false);   realXHR.addEventListener('timeout', function () {    //記錄埋點(diǎn)   }, false);  return realXHR; }復(fù)制代碼

代理 Fetch

 const oldFetch = window.fetch;  function newFetch(url, init) {    const fetchObj = {      url: url,      method: method,      body: body,     }     ajaxEventTrigger.call(fetchObj, AJAX_START);    return oldFetch.apply(this, arguments).then(function (response) {      if (response.ok) {       //記錄埋點(diǎn)       } else {       //上報(bào)錯(cuò)誤       }      return response     }).catch(function (error) {       fetchObj.error = error        //記錄埋點(diǎn)               throw error     })   }復(fù)制代碼

監(jiān)聽(tīng)頁(yè)面的 PVUV

在進(jìn)入頁(yè)面時(shí),我們通過(guò)算法生成一個(gè)唯一 session id,作為這次埋點(diǎn)行為的全局 id,上報(bào)用戶 id,設(shè)備指紋,設(shè)備信息。在用戶未登錄的情況下,通過(guò)設(shè)備指紋來(lái)計(jì)算 UV,通過(guò) session id計(jì)算 PV

異常捕獲

異常就是干擾程序的正常流程的不尋常事故

RUNTIME ERROR

JS中可以通過(guò) window.onerrorwindow.addEventListener('error', callback) 捕捉運(yùn)行時(shí)異常,一般使用window.onerror,它兼容性更好。

window.onerror = function(message, url, lineno, columnNo, error) {    const lowCashMessage = message.toLowerCase()    if(lowCashMessage.indexOf('script error') > -1) {      return     }    const detail = {      url: url           filename: filename,      columnNo: columnNo,      lineno: lineno,      stack: error.stack,      message: message     }    //記錄埋點(diǎn)}復(fù)制代碼

Script Error

在這里我們過(guò)濾了 Script Error, 它產(chǎn)生的原因主要是頁(yè)面中加載的第三方跨域腳本報(bào)錯(cuò),比如托管在第三方 CDN 中的 js 腳本。這類問(wèn)題比較難以排查。解決的方法有:

  • 打開(kāi) CORS(Cross Origin Resource Sharing,跨域資源共享),如下步驟
    • <srcipt src="another domain/main.js" cossorigin="anonymous"></script>
    • 修改Access-Control-Allow-Origin: * | 指定域名
  • 使用 try catch
      <script scr="crgt.js"></script> //加載crgt腳本,window.crgt = {getUser: () => string}   try{      window.crgt.getUser();   }catch(error) {      throw error // 輸出正確的錯(cuò)誤堆棧   }復(fù)制代碼

Promise reject

js 在異步異常時(shí)無(wú)法通過(guò) onerror 方法捕獲 ,在 Promise 對(duì)象在 reject 時(shí),同時(shí)并沒(méi)有進(jìn)行處理時(shí) 會(huì)拋出一個(gè) unhandledrejection 的錯(cuò)誤,并不會(huì)被上述的方法所捕獲,所以需要添加單獨(dú)的處理事件。

window.addEventListener("unhandledrejection", event => {  throw event.reason });復(fù)制代碼

資源加載異常

在瀏覽器中,可以通過(guò) window.addEventListener('error', callback) 的方式監(jiān)聽(tīng)資源加載異常,比如 js 或者 css 腳本文件丟失。

window.addEventListener('error', (event) => {  if (event.target instanceof HTMLElement) {    const target = parseDom(event.target, ['src']);    const detail = {      target: target,      path: parseXPath(target),     }    //  記錄埋點(diǎn)   } }, true)復(fù)制代碼

監(jiān)聽(tīng)用戶行為

通過(guò) addEventListener click 監(jiān)聽(tīng) click 事件

window.addEventListener('click', (event) => {    //記錄埋點(diǎn)}, true)復(fù)制代碼

在這里通過(guò)組件的 displaName 來(lái)定位元素的位置,displaName 表示組件的文件目錄,比如 src/components/Form.js 文件導(dǎo)出的組件 FormItem 通過(guò) babel plugin 自動(dòng)添加屬性 @components/Form.FormItem,或者使用者主動(dòng)給組件添加 static 屬性 displayName

頁(yè)面路由變化

  • hashRouter 監(jiān)聽(tīng)頁(yè)面hash變化,對(duì)hash進(jìn)行解析
window.addEventListener('hashchange', event => {  const { oldURL, newURL } = event;  const oldURLObj = url.parseUrl(oldURL);  const newURLObj = url.parseUrl(newURL);  const from = oldURLObj.hash && url.parseHash(oldURLObj.hash);  const to = newURLObj.hash && url.parseHash(newURLObj.hash);  if(!from && !to ) return;  // 記錄埋點(diǎn)})復(fù)制代碼

監(jiān)聽(tīng)頁(yè)面離開(kāi)

通過(guò) addEventListener beforeunload 監(jiān)聽(tīng)離開(kāi)頁(yè)面事件

window.addEventListener('beforeunload', (event) => {    //記錄埋點(diǎn)})復(fù)制代碼

SDK 架構(gòu)

class Observable {    constructor(observer) {         observer(this.emit)     }     emit = (data) => {        this.listeners.forEach(listener => {             listener(data)         })     }     listeners = [];          subscribe = (listener) => {        this.listeners.push(listeners);        return () => {            const index = this.listeners.indexOf(listener);            if(index === -1) {                return false             }                         this.listeners.splice(index, 1);            return true;         }      } }復(fù)制代碼
const clickObservable = new Observable((emit) => {    window.addEventListener('click', emit) })復(fù)制代碼

然而在處理 ajax,需要將多種數(shù)據(jù)組合在一起,需要進(jìn)行 merg 操作,則顯得沒(méi)有那么優(yōu)雅,也很難適應(yīng)后續(xù)復(fù)雜的數(shù)據(jù)流的操作。

const ajaxErrorObservable = new Observable((emit) => {    window.addEventListener(AJAX_ERROR, emit) })const ajaxSuccessObservable = new Observable((emit) => {    window.addEventListener(AJAX_SUCCESS, emit) })const ajaxTimeoutObservable = new Observable((emit) => {    window.addEventListener(AJAX_TIMEOUT, emit) })復(fù)制代碼

可以選擇 RxJS 來(lái)優(yōu)化代碼

export const ajaxError$ = fromEvent(window, 'AJAX_ERROR', true)export const ajaxSuccess$ = fromEvent(window, 'AJAX_SUCCESS', true)export const ajaxTimeout$ = fromEvent(window, 'AJAX_TIMEOUT', true)復(fù)制代碼
ajaxError$.pipe(     merge(ajaxSuccess$, ajaxTimeout$),      map(data=> (data) => ({category: 'ajax', data; data}))     subscribe(data => console.log(data))復(fù)制代碼

通過(guò) merge, map 兩個(gè)操作符完成對(duì)數(shù)據(jù)的合并和處理。

數(shù)據(jù)流

初探埋點(diǎn)系統(tǒng)

項(xiàng)目結(jié)構(gòu)

  • core
    • event$ 數(shù)據(jù)流合并
    • snapshot 獲取當(dāng)前設(shè)備快照,例如urluserIDrouter
    • track 埋點(diǎn)類,組合數(shù)據(jù)流和日志。
  • logger
    • logger 日志類
      • info
      • warn
      • debug
      • error
  • observable
    • ajax
    • beforeUpload
    • opeartion
    • routerChange
    • logger
    • track

參考

  • www.alibabacloud.com/help/zh/doc…

結(jié)尾

自建埋點(diǎn)系統(tǒng)是一個(gè)需要前后端一起合作的事情,如果人力不足的情況下,建議使用第三方分析插件,例如 Sentry 就能足夠滿足大部分日常使用

但還是建議多了解,在第三方插件出現(xiàn)不能滿足業(yè)務(wù)需求的時(shí)候,可以頂上。

想了解

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
免费无码不卡视频在线观看| 欧美与动交zoz0z| 亚洲激情在线看| 亚洲欧美久久久久| 一女被多男玩喷潮视频| 精品久久久99| 成人在线观看a| www.国产二区| 国产999免费视频| 国产第一页视频| 国产欧美日韩小视频| 国产成人精品免费看在线播放 | 99色精品视频| 97视频在线免费| 成人免费a级片| 国产高清不卡无码视频| 五月天av影院| 成年人网站av| 一区二区在线免费看| 午夜免费高清视频| 天堂在线资源视频| 黑森林精品导航| 午夜激情福利在线| 色婷婷一区二区三区av免费看| 精品久久久久久中文字幕2017| 久久精品.com| 一区二区三区韩国| 亚洲欧美日韩综合网| 天天操天天干天天做| 一级片免费在线观看视频| 亚洲高清视频免费| 欧美爱爱视频网站| 大陆极品少妇内射aaaaaa| 日本人体一区二区| 国产亚洲天堂网| 国产永久免费网站| www插插插无码免费视频网站| 中文精品无码中文字幕无码专区| 黄色大片中文字幕| 激情五月开心婷婷| 黄色手机在线视频| 一级片黄色免费| 亚洲 自拍 另类小说综合图区| 欧美二区在线视频| 亚洲男人天堂av在线| 一区二区三区一级片| 波多野结衣家庭教师在线| 日日橹狠狠爱欧美超碰| 国内外成人免费在线视频| 国产人妻互换一区二区| 国产l精品国产亚洲区久久| 亚洲免费av一区| 国产精品国产亚洲精品看不卡| 国产乱子夫妻xx黑人xyx真爽| 女人高潮一级片| 波多野结衣50连登视频| 亚洲综合日韩欧美| www.国产在线播放| 天天操天天干天天做| 每日在线观看av| 超碰中文字幕在线观看| 男人日女人bb视频| 日本精品免费视频| 自拍偷拍21p| 福利视频一二区| 亚洲小说欧美另类激情| 日本va中文字幕| 日韩五码在线观看| 99热这里只有精品7| 三级在线视频观看| 国产二区视频在线播放| 法国空姐在线观看免费| 亚洲xxx在线观看| 男女视频一区二区三区| 国产肉体ⅹxxx137大胆| 四虎1515hh.com| 日韩爱爱小视频| 欧美自拍小视频| 成人一级片网站| 国产最新免费视频| www一区二区www免费| 日本久久久网站| 99久久免费观看| 99国产精品白浆在线观看免费| 亚洲欧美一二三| 手机看片日韩国产| 国产奶头好大揉着好爽视频| 国产乱码一区二区三区四区| 日本肉体xxxx裸体xxx免费| 久久综合伊人77777麻豆最新章节| 欧美国产激情视频| 国产黄色特级片| 九热视频在线观看| 8x8x最新地址| 欧美成人福利在线观看| 99精品999| 男女爱爱视频网站| 男人天堂av片| 成年人视频观看| 国产a级片免费观看| 一本岛在线视频| 9999在线观看| a级黄色小视频| 日韩av资源在线| 天天干天天草天天| 四虎成人在线播放| a级片一区二区| av之家在线观看| 久久99999| 久久久国内精品| 日韩欧美精品在线观看视频| 天天天干夜夜夜操| 特级黄色录像片| 国产视频九色蝌蚪| 岛国毛片在线播放| 六月婷婷激情综合| 蜜臀视频一区二区三区| 国产精品无码乱伦| 男女视频网站在线观看| 天天操天天爱天天爽| 91免费版看片| 午夜免费福利在线| 亚洲av首页在线| 狠狠操精品视频| dy888午夜| 欧美 日韩 国产 激情| 中国一级黄色录像| 十八禁视频网站在线观看| 精品国产无码在线| 日韩精品一区中文字幕| 久久久久亚洲av无码专区喷水| 97xxxxx| 老司机激情视频| 182午夜在线观看| 九一免费在线观看| 中文字幕成人免费视频| 精品国产一区三区| www.午夜av| 8x8x最新地址| 国产精品无码一区二区在线| 自拍偷拍视频在线| 中文字幕 91| 国产在线青青草| 97视频在线免费| 天天综合五月天| 999热精品视频| 欧美在线aaa| 老熟妇仑乱视频一区二区| 日韩 欧美 视频| 91国在线高清视频| 亚洲在线观看网站| 久久久久久久久久一区| 午夜dv内射一区二区| 国产在线观看福利| 鲁一鲁一鲁一鲁一澡| 日韩精品一区二区免费| 特级黄色录像片| 波多野结衣激情| 精品国产鲁一鲁一区二区三区| 91极品尤物在线播放国产| 日韩中文字幕免费在线 | 国产免费内射又粗又爽密桃视频| 可以看污的网站| 日韩av加勒比| 色黄视频免费看| 男人午夜视频在线观看| 男人的天堂最新网址| 精品综合久久久久| 中文字幕一区久久| 激情成人在线观看| 老司机av福利| 亚洲精品久久久久久久蜜桃臀| 成人av在线不卡| 国产精品无码一区二区在线| 免费成人在线视频网站| 日韩精品一区二区三区色欲av| 天天干在线影院| 欧美aaa在线观看| 可以在线看黄的网站| 国产freexxxx性播放麻豆| 怡红院av亚洲一区二区三区h| 免费成人午夜视频| 免费观看成人网| 三级av免费看| 波多野结衣综合网| av网址在线观看免费| 天美一区二区三区| 欧美在线一区视频| 中文字幕欧美人妻精品一区| 天美一区二区三区| 五十路熟女丰满大屁股| 一区二区在线播放视频| 久久久精品视频国产| 日本免费不卡一区二区| 老司机午夜性大片| 国产精品一色哟哟| 亚洲36d大奶网| 乱人伦xxxx国语对白| 久久久精品高清| 草草久久久无码国产专区|