前端早早聊大會,前端成長的新起點,與掘金聯合舉辦。 加微信 codingdreamer 進大會專屬內推羣,贏在新的起跑線。前端
第十四屆|前端成長晉升專場,8-29 即將直播,9 位講師(螞蟻金服/稅友等),點我上車👉 (報名地址):node
在去年,有過一次文字版的分享,當時系統尚未徹底建設成型,你們能夠結合這兩篇一塊兒看: 技術探索:60 天急速自研-前端埋點監控跟蹤系統大浪子。react
本文爲第五屆 - 前端監控體系建設專場講師 - Jimmy 的分享 - 簡要講稿版(完整版請看錄播視頻):小程序
從宋小菜的第一款 APP 上線至今已經 5 年左右時間,咱們的端應用類型也由 RN APP 逐漸過渡到 RN APP/PC/H5/小程序 等多種類型共存的狀況,咱們從 19 年開始就開始研發本身的 埋點監控系統 並在 19 年年末初步成型上線一直運行到如今,此次分享我將從如下幾個方面去介紹咱們是如何研發出現在的埋點監控系統的:
後端
首先來說一下咱們設計這個監控系統的設計思路。
微信小程序
前端監控的基本目的在咱們看來是如下幾點:api
基於以上咱們對監控體系的思考,小菜前端在這 5 年中逐步完善了本身的監控體系,這差很少就是咱們監控體系的一個簡單的發展史:
對於研發成本的考慮是形成上面發展史造成的根本緣由:promise
接下來就應該考慮如何設計這個系統了,系統包含埋點和監控兩部分,因爲本次主題是監控,因此這裏就講監控系統相關的基礎模塊:
瀏覽器
如下是系統目前的基礎架構:
緩存
客戶端目前覆蓋到了 PC/H五、RN 應用、小程序,因爲 node 應用還比較少應用到業務中,考慮到投入產出比,尚未進行 SDK 的研發。
日誌處理通過三層:
這裏即是第三層的日誌處理:
如下則是展現監控系統中從數據上報到展現的整個數據流向全過程
接下來就簡單講一下 SDK 的實現
首先要考慮的是應該採集哪些數據
雖然是監控錯誤數據,可是有時候爲了分析錯誤的造成緣由或者重現錯誤出現的場景,咱們仍是須要用到用戶的行爲數據的,所以須要採集的數據包括兩方面:
用戶行爲數據:
錯誤數據
因爲時間緣由,這裏簡單講一下兩個端的 SDK 的簡單實現:
RN SDK
小菜的 RN 應用是比較純粹的 RN 應用,因此 RN SDK 實現能夠簡單地分爲兩端:
JS 端
Native 端
代碼展現
Promise.rejectionTracking 的代碼展現
const tracking = require("promise/setimmediate/rejection-tracking");
tracking.disable(); tracking.enable({ allRejections: true, onHandled: () => { // We do nothing }, onUnhandled: (id: any, error: any) => { const stack = computeStackTrace(error); stack.mechanism = 'unhandledrejection'; stack.data = { id } // tslint:disable-next-line: strict-type-predicates if (!stack.stack) { stack.stack = []; } Col.trackError(stringifyMsg(stack)) } }); 複製代碼
微信小程序 SDK
這裏簡單講一下微信小程序 SDK 實現的兩個方面:
網絡請求
代理全局對象 wx 的 wx.request 方法:
import "miniprogram-api-typings"
export const wrapRequest = () => { const originRequest = wx.request; wx.request = function(...args: any[]): WechatMiniprogram.RequestTask { // get request data return originRequest.apply(this, ...args); // } } 複製代碼
頁面跳轉
覆寫 Page/Component 對象,代理其生命週期方法:
/* global Page Component */
function captureOnLoad(args) { console.log('do what you want to do', args) } function captureOnShow(args) { console.log('do what you want to do', args) } function colProxy(target, method, customMethod) { const originMethod = target[method] if(target[method]){ target[method] = function() { customMethod(…arguments) originMethod.apply(this, arguments) } } } // Page const originalPage = Page Page = function (opt) { colProxy(opt.methods, 'onLoad', captureOnLoad) colProxy(opt.methods, 'onShow', captureOnShow) originalPage.apply(this, arguments) } // Component const originalComponent = Component Component = function (opt) { colProxy(opt.methods, 'onLoad', captureOnLoad) colProxy(opt.methods, 'onShow', captureOnShow) originalComponent.apply(this, arguments) } 複製代碼
接下來就講一下咱們是如何作日誌處理的:
首先展現一下日誌處理模塊(咱們稱之爲 log-transfer)的基本結構:
數據上報屬於處理原始數據的第一層,包含如下特色
日誌上報處理中有很多須要注意的要點,這裏挑幾點簡單說一下:
接下來簡單講一下監控看板:
一線是監控看板的一些簡單展現截圖
看板的做用包括:
什麼是 issue? 即對已經上報的同類型錯誤進行概括和總結之後抽象出來的數據,便於咱們對同一種的錯誤進行跟蹤和處理。
Issue 存在明確的生命週期,這裏展現的就是咱們的 issue 生命週期:
如下是一個錯誤詳情的示例:
使用 source map 轉換後的堆棧信息也會展示在錯誤詳情中。
接下來說一下咱們是如何設計和開發報警控制模塊的:
結構
首先是系統結構:
做用
錯誤信息特徵
前面解釋了什麼是 issue ,可是沒有說明 issue 是如何抽象出來的,這裏給你們簡單解釋一下,以 JS 錯誤爲例:
JS 錯誤咱們在上報時使用 Tracekit 進行標準化,從而獲得具備統一結構的錯誤信息,而後據此判斷和歸類錯誤,參考字段包括:
如下是系統 ISSUE 的展現:
ISSUE 的每一次狀態更新都會被記錄下來
Kafka 的做用
Kafka 的做用主要包括:
爲何不使用實時通訊(socketIO/RPC)?總的來講是爲了系統穩定性考慮
固然,Kafka 也有替代方案,如 Redis/RabbitMQ 等。
報警任務設計
報警任務設計在報警系統中屬於比較重要的部分,咱們大體將其抽象成兩大部分:
數據結構示例
下面給出一個簡單的報警任務數據結構示例:
報警任務是能夠人爲設置和控制的
而後就是系統中最後的一個模塊,任務執行模塊(咱們稱之爲 Inspector):
任務執行器則比較簡單,主要用於執行控制器分發的報警任務,查詢上報的線上數據根據任務的判斷規則生成相應的任務結果並經過 Kafka 返回給任務控制器,因爲報警任務可能較多因此採用集羣的方式部署,多節點分散任務壓力:
最後再放出在以前給出的各模塊之間的 數據流向圖,不知道你們是否清楚一些了:
整個系統的主要模塊和數據流通都在這張圖上。
個人演講就此結束,謝謝你們!
本文使用 mdnice 排版