您好,登錄后才能下訂單哦!
這篇文章主要介紹了埋點系統是什么,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。
最近雜七雜八的事情比較多,難得抽出時間來彌補一下之前的系列,欠大家的埋點系列現在開始走起來
前端開發攻城獅開開心心的 coding,非常自豪的進行了業務、UI 分離開發,各種設計模式、算法優化輪番上陣,代碼寫的 Perfect(勞資代碼天下第一),沒有 BUG,程序完美,兼容性 No.1,代碼能打能抗質量高。下班輕松打卡,回家看娃。
實際上,開發環境與生產環境并不能等同,并且測試的過程再完善,依然會有漏測的情況存在。考慮到用戶使用客戶端環境、網絡環境等等一系列的不確定因素存在。
所以在開發過程中一定要記得三大原則(我胡謅的)
埋點就像城市中的攝像頭,從產品的角度考慮,它可以監控到用戶在我們產品里的行為軌跡,為產品的迭代、項目的穩定提供依據,WHO、WHEN、WHERE、HOW、WHAT 是埋點采集數據的基礎維度。
對前端開發而言,可以監控頁面資源加載性能,異常等等,提供了頁面體驗和健康指數,為后續性能優化提供依據,及時上報異常和發生場景。從而能夠及時修正問題,提高項目質量等。
埋點可以大概分為三類:
代碼埋點 | 可視化埋點 | 無痕埋點 | |
---|---|---|---|
典型場景 | 無痕埋點無法覆蓋到,比如需要業務數據 | 簡單規范的頁面場景 | 簡單規范的頁面場景, |
優勢 | 業務數據明確 | 開發成本低,運營人員可直接進行相關埋點配置 | 無需配置,數據可回溯 |
不足 | 數據不可回溯,開發成本高 | 不能關聯業務數據,數據不可回溯 | 數據量較大,不能關聯業務數據 |
大部分情況,我們可以通過無痕埋點收集到所有的信息數據,再配合可視化埋點,能夠具體定位到某一個點位,這樣大部分的埋點信息都據此分析出來。
在特殊情況下,可以多加上業務代碼手動埋點,處理一下特別的場景(大部分情況是走強業務與正常的點擊,刷新事件無關需要上報的信息)
上面的數據通過 3 個維度來定義埋點事件
LEVEL
: 描述埋點數據的日志級別INFO
:一些用戶操作,請求成功,資源加載等等正常的數據記錄ERROR
: JS報錯,接口報錯等等錯誤類型的數據記錄DEBUG
: 預留開發人員通過手動調用的方式回傳排除bug的數據記錄WARN
: 預留開發人員通過手動調用的方式回傳非正常用戶行為的的數據記錄CATEGORY
:描述埋點數據的分類TRACK
: 埋點SDK對象的生命周期管理整個埋點數據。WILL_MOUNT
:sdk對象即將初始化加載,生成一個默認ID,跟蹤全部相關事件DID_MOUNTED
:sdk對象初始化完成,主要獲取設備指紋等等的異步操作完成AJAX
: AJAX相關數據ERROR
:頁面中的異常相關數據PERFORMANCE
: 關于性能相關數據OPERATION
: 用戶操作相關數據EVENT_NAME
:具體的事件名稱根據上述的維度,我們可以簡單設計如下的架構
根據上圖的架構,再進行下面的具體代碼開發
在瀏覽器中現在主要有 2 種請求方式,一個是 XMLHttpRequest
, 一個是 Fetch
。
function NewXHR() { var realXHR: any = new OldXHR(); // 代理模式里面有提到過 realXHR.id = guid() const oldSend = realXHR.send; realXHR.send = function (body) { oldSend.call(this, body) //記錄埋點 } realXHR.addEventListener('load', function () { //記錄埋點 }, false); realXHR.addEventListener('abort', function () { //記錄埋點 }, false); realXHR.addEventListener('error', function () { //記錄埋點 }, false); realXHR.addEventListener('timeout', function () { //記錄埋點 }, false); return realXHR; }復制代碼
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) { //記錄埋點 } else { //上報錯誤 } return response }).catch(function (error) { fetchObj.error = error //記錄埋點 throw error }) }復制代碼
PV
,UV
在進入頁面時,我們通過算法生成一個唯一 session id
,作為這次埋點行為的全局 id,上報用戶 id,設備指紋,設備信息。在用戶未登錄的情況下,通過設備指紋來計算 UV
,通過 session id
計算 PV
。
異常就是干擾程序的正常流程的不尋常事故
在JS
中可以通過 window.onerror
和window.addEventListener('error', callback)
捕捉運行時異常,一般使用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 } //記錄埋點}復制代碼
在這里我們過濾了 Script Error
, 它產生的原因主要是頁面中加載的第三方跨域腳本報錯,比如托管在第三方 CDN 中的 js
腳本。這類問題比較難以排查。解決的方法有:
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 // 輸出正確的錯誤堆棧 }復制代碼
js
在異步異常時無法通過 onerror
方法捕獲 ,在 Promise 對象在 reject 時,同時并沒有進行處理時
會拋出一個 unhandledrejection
的錯誤,并不會被上述的方法所捕獲,所以需要添加單獨的處理事件。
window.addEventListener("unhandledrejection", event => { throw event.reason });復制代碼
在瀏覽器中,可以通過 window.addEventListener('error', callback)
的方式監聽資源加載異常,比如 js
或者 css
腳本文件丟失。
window.addEventListener('error', (event) => { if (event.target instanceof HTMLElement) { const target = parseDom(event.target, ['src']); const detail = { target: target, path: parseXPath(target), } // 記錄埋點 } }, true)復制代碼
通過 addEventListener click
監聽 click
事件
window.addEventListener('click', (event) => { //記錄埋點}, true)復制代碼
在這里通過組件的 displaName
來定位元素的位置,displaName
表示組件的文件目錄,比如 src/components/Form.js
文件導出的組件 FormItem
通過 babel plugin
自動添加屬性 @components/Form.FormItem
,或者使用者主動給組件添加 static
屬性 displayName
。
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; // 記錄埋點})復制代碼
通過 addEventListener beforeunload
監聽離開頁面事件
window.addEventListener('beforeunload', (event) => { //記錄埋點})復制代碼
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; } } }復制代碼
const clickObservable = new Observable((emit) => { window.addEventListener('click', emit) })復制代碼
然而在處理 ajax
,需要將多種數據組合在一起,需要進行 merg 操作,則顯得沒有那么優雅,也很難適應后續復雜的數據流的操作。
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) })復制代碼
可以選擇 RxJS 來優化代碼
export const ajaxError$ = fromEvent(window, 'AJAX_ERROR', true)export const ajaxSuccess$ = fromEvent(window, 'AJAX_SUCCESS', true)export const ajaxTimeout$ = fromEvent(window, 'AJAX_TIMEOUT', true)復制代碼
ajaxError$.pipe( merge(ajaxSuccess$, ajaxTimeout$), map(data=> (data) => ({category: 'ajax', data; data})) subscribe(data => console.log(data))復制代碼
通過 merge
, map
兩個操作符完成對數據的合并和處理。
core
event$
數據流合并snapshot
獲取當前設備快照,例如url
,userID
,router
track
埋點類,組合數據流和日志。logger
logger
日志類info
warn
debug
error
observable
ajax
beforeUpload
opeartion
routerChange
logger
track
自建埋點系統是一個需要前后端一起合作的事情,如果人力不足的情況下,建議使用第三方分析插件,例如 Sentry 就能足夠滿足大部分日常使用。
感謝你能夠認真閱讀完這篇文章,希望小編分享埋點系統是什么內容對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,遇到問題就找億速云,詳細的解決方法等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。