应用实时监控 ARMS 上线用户行为回溯功能
隨著前端技術(shù)日新月異迅猛發(fā)展,為了實(shí)現(xiàn)更好的前端性能,最大程度提高用戶體驗(yàn),支持單頁應(yīng)用的框架逐漸占領(lǐng)市場(chǎng),如眾所周知的React,Vue等等。但是在單頁應(yīng)用的趨勢(shì)下,快速定位并解決JS錯(cuò)誤卻成為一大難題。在當(dāng)下的互聯(lián)網(wǎng)行業(yè),對(duì)前端性能要求越來越高,前端性能監(jiān)控的產(chǎn)品層出不窮,javascript錯(cuò)誤診斷更是其中舉足輕重的一個(gè)環(huán)節(jié)。幫助開發(fā)者排查線上bug,實(shí)現(xiàn)快速定位問題,高效解決問題,是我們努力的方向。
一、JS錯(cuò)誤診斷
目前已經(jīng)有了許多諸如Arms,Sentry等前端性能監(jiān)控框架,都在一定程度上對(duì)JS錯(cuò)誤診斷提供了相應(yīng)的 支持,總體來說,大家的思路比較相似,可以總結(jié)為以下幾個(gè)步驟:
1. 統(tǒng)計(jì)JS錯(cuò)誤
每當(dāng)上線一個(gè)新的產(chǎn)品或新的業(yè)務(wù)功能,往往伴隨著一些不可避免的線上bug,這些bug發(fā)生的頻率有多高、發(fā)生在什么頁面、影響了多少用戶等等,對(duì)于判斷解決問題的優(yōu)先級(jí)、幫助排查問題和優(yōu)化性能來說是非常關(guān)鍵的。
圖1是Arms前端性能監(jiān)控的JS錯(cuò)誤診斷診斷頁面,可以清晰地看到錯(cuò)誤發(fā)生的次數(shù)、影響用戶數(shù)以及錯(cuò)誤分布情況等信息,開發(fā)者可以根據(jù)這些統(tǒng)計(jì)數(shù)據(jù)更好地決策問題的輕重緩急,使性能優(yōu)化有條不紊進(jìn)行。
?
圖1. JS錯(cuò)誤總覽
2. 精準(zhǔn)定位錯(cuò)誤
前端報(bào)錯(cuò)的原因有很多,網(wǎng)絡(luò)因素、瀏覽器兼容性、用戶操作邏輯、業(yè)務(wù)代碼本身的問題等等都可能導(dǎo)致故障發(fā)生,在JS錯(cuò)誤統(tǒng)計(jì)中我們已經(jīng)知道了錯(cuò)誤發(fā)生的頁面,這在一定程度上縮小了排查范圍,但這樣還是不夠的,我們還想要知道更多錯(cuò)誤詳情,比如:
1)現(xiàn)場(chǎng)信息
包括報(bào)錯(cuò)的設(shè)備、操作系統(tǒng)、瀏覽器等等,這些信息無疑可以幫助開發(fā)者更好地復(fù)現(xiàn)問題,進(jìn)而修復(fù)bug。
?
圖2. JS錯(cuò)誤概要
2)代碼追蹤
利用error stack和source map來精準(zhǔn)定位發(fā)生錯(cuò)誤的代碼位置。
?
a. 上傳source map文件
b. 在代碼中定位錯(cuò)誤
圖3. source map錯(cuò)誤定位
3. 還原報(bào)錯(cuò)現(xiàn)場(chǎng)
還原錯(cuò)誤發(fā)生時(shí)用戶行為上下文是JS錯(cuò)誤診斷的最后一步,也是最關(guān)鍵和最困難的一步。
假設(shè)以下場(chǎng)景:我們收到用戶反饋說點(diǎn)了某按鈕后沒有反應(yīng)……
面對(duì)用戶反饋,我們不由得會(huì)想,沒反應(yīng)是什么原因呢,是點(diǎn)擊事件的handler出錯(cuò)了導(dǎo)致接口請(qǐng)求沒發(fā)出?還是接口掛了?或者是接口返回?cái)?shù)據(jù)渲染失敗了?
類似以上的困惑應(yīng)該很多開發(fā)者都會(huì)時(shí)常遇到,我們不可能去指揮用戶打開開發(fā)者工具再一步步debug給我們看,這就需要我們的前端監(jiān)控平臺(tái)具備還原報(bào)錯(cuò)現(xiàn)場(chǎng)的能力,幫助開發(fā)者了解錯(cuò)誤發(fā)生時(shí)候的用戶行為上下文,進(jìn)而可以預(yù)想一下剛才的場(chǎng)景——
根據(jù)用戶的uid等信息,我們可以回溯到該用戶報(bào)錯(cuò)前后的一系列操作以及前端行為:
進(jìn)入頁面->點(diǎn)擊按鈕->發(fā)出api請(qǐng)求成功-> js error……
于是我們可以知道報(bào)錯(cuò)是發(fā)生在api請(qǐng)求成功后的數(shù)據(jù)處理環(huán)節(jié),再依據(jù)步驟2中提供的錯(cuò)誤詳情快速解決問題。
二、用戶行為回溯
已經(jīng)有一些前端性能監(jiān)控平臺(tái)接入了用戶行為監(jiān)控,實(shí)現(xiàn)的方式也各有千秋,主要流程可以分為三個(gè)步驟:行為采集、行為上報(bào)、行為回溯。
1. 行為采集
1)哪些行為需要采集?
我們站在用戶的立場(chǎng)去考慮一個(gè)單頁應(yīng)用的瀏覽周期內(nèi)的可能流程:進(jìn)入應(yīng)用首頁——加載頁面內(nèi)容——瀏覽頁面內(nèi)容——用戶交互(鼠標(biāo)交互/鍵盤交互等)——跳轉(zhuǎn)到新頁面……
要將用戶行為串聯(lián)成完整的行為鏈來為js error提供上下文,我們需要知道什么時(shí)間,什么位置,發(fā)生了什么事情。由此,以上用戶瀏覽過程中的所有的頁面行為(包括但不僅限于用戶交互)可以用以下幾類來大致概括:
Api請(qǐng)求,鼠標(biāo)事件,鍵盤事件,路由跳轉(zhuǎn),error 等。
2)如何采集?
在確定了哪些行為需要上報(bào)以后,我們?cè)僭趤砜慈绾瓮瓿尚袨榇螯c(diǎn)。
在過往的時(shí)代,我們有傳統(tǒng)的手動(dòng)埋點(diǎn)方法,它的缺點(diǎn)也是不言而喻的:手動(dòng)埋點(diǎn)是容易混亂的,有時(shí)可能會(huì)出現(xiàn)錯(cuò)埋、漏埋等情況,每每上線一個(gè)新功能,需要開發(fā)團(tuán)隊(duì)和數(shù)據(jù)團(tuán)隊(duì)進(jìn)行埋點(diǎn)溝通,徒增了時(shí)間和人力成本;其次時(shí)常因?yàn)楫a(chǎn)品排期緊張,功能急于上線,就不得不先砍掉了埋點(diǎn)的需求,在后續(xù)的版本更新中再補(bǔ)上,這使得新上線的功能得不到驗(yàn)證,而新上線的功能對(duì)業(yè)務(wù)和產(chǎn)品性能的影響都很關(guān)鍵。
現(xiàn)如今,一個(gè)好的前端監(jiān)控產(chǎn)品需要實(shí)現(xiàn)“無埋點(diǎn)”監(jiān)控,充當(dāng)一雙眼睛,時(shí)時(shí)刻刻監(jiān)控著產(chǎn)品的運(yùn)作情況,全量采集頁面事件和用戶行為,為業(yè)務(wù)分析和錯(cuò)誤診斷都提供充足的信息。
?
圖4. 用戶行為采集流程圖
以上流程圖為Arms做行為采集的大致步驟,首先需要在正常的html頁面中插入一小段js代碼,即引入我們具有行為日志采集功能的SDK,如下代碼所示,通過createElement(“script”)在Dom節(jié)點(diǎn)添加script的元素,并將SDK的js文件引入進(jìn)來,用于收集用戶行為,并在適當(dāng)?shù)臅r(shí)候上報(bào)到后端,具體方法如下代碼所示,其中bl.js為SDK文件。
<script> !(function(c,b,d,a){c[a]||(c[a]={});c[a].config={pid:"xxxxxxx",appType:"web",imgUrl:"https://arms-retcode.aliyuncs.com/r.png?"}; with(b)with(body)with(insertBefore(createElement("script"),firstChild))setAttribute("crossorigin","",src=d) })(window,document,"https://retcode.alicdn.com/retcode/bl.js","__bl"); </script>3)SDK中行為采集的實(shí)現(xiàn)
- API行為采集
重寫原生XMLHttpRequest或fetch方法,采集必要的API信息(如url,狀態(tài)碼,狀態(tài)message等)。
- 控制臺(tái)行為采集
重寫console的常見控制臺(tái)輸出方法,比如: log,warning,error等。
注意,通過重寫 console 對(duì)象監(jiān)控瀏覽器控制臺(tái)的打印信息,這樣會(huì)導(dǎo)致在控制臺(tái)下打印的日志無法正確看到原代碼文件中的位置,console的位置會(huì)定位到SDK的代碼中,可以通過配置瀏覽器 Blackboxing來解決。
?
圖5. console定位在SDK代碼中
- 用戶交互行為采集(鼠標(biāo)鍵盤事件等):?
可以在頂層的document上全面監(jiān)聽各類用戶交互事件,如click,keypress,mousemove,scroll等等。但是這種方法也有一個(gè)明顯的缺陷,假設(shè)用戶監(jiān)聽了某個(gè)dom上的click事件,并且設(shè)置了event.stopPropagation(),這種情況的點(diǎn)擊事件是無法被document監(jiān)聽到的,而往往這類行為對(duì)于錯(cuò)誤診斷和業(yè)務(wù)分析都尤為重要。解決方法是在addEventListener中埋入鉤子。
- 路由跳轉(zhuǎn)行為采集
路由跳轉(zhuǎn)無疑會(huì)觸發(fā)瀏覽器歷史記錄的改變,每當(dāng)處于激活狀態(tài)的歷史記錄條目發(fā)生變化時(shí),window的popstate事件會(huì)觸發(fā),但是調(diào)用history.pushState()或者h(yuǎn)istory.replaceState()不會(huì)觸發(fā)popstate事件。因此路由跳轉(zhuǎn)的監(jiān)控可以分為兩個(gè)方面,一方面在window. onpopstate中埋入鉤子,另一方面在history.pushState和history.replaceState中埋入鉤子。
- js error
全局監(jiān)聽js error:
監(jiān)聽全局未處理的rejection:
window.addEventListener('unhandledrejection', function(event){...})2. 行為上報(bào)
SDK采集到用戶行為后,以一定的格式進(jìn)行信息拼接,然后偽裝成圖片發(fā)送給后端。為什么要使用圖片來發(fā)送日志信息而不是直接使用ajax呢?這是因?yàn)镾DK的script文件和后端分析的代碼可能不在相同的域內(nèi),而將image對(duì)象的src屬性指向后端腳本并攜帶參數(shù),可以輕松實(shí)現(xiàn)跨域請(qǐng)求。不同平臺(tái)對(duì)于前端監(jiān)控行為的類別都比較類似,但上報(bào)的方式還是不盡相同的,服務(wù)于不同的業(yè)務(wù)需求。以下是兩種比較典型的行為上報(bào)形式:
1)持續(xù)全量上報(bào)
圖6是截取的New relic的行為日志上報(bào)信息,為什么稱之為持續(xù)全量上報(bào)呢?“持續(xù)”是指它的行為日志是定時(shí)上報(bào)的,每隔幾秒便會(huì)上報(bào)一次,上報(bào)請(qǐng)求非常密集。“全量”則是指它采集的行為類型覆蓋面很廣,可以從上報(bào)的Request Payload中看到,它采集的不僅限于我們上面提到的一些主要的頁面行為,它幾乎覆蓋了所有的頁面事件,包括鼠標(biāo)移動(dòng)等等。而這種上報(bào)方式也是利弊參半:
優(yōu)點(diǎn):它可以更真實(shí)地還原用戶在整個(gè)頁面周期內(nèi)的行為,保真度很高,對(duì)于還原現(xiàn)場(chǎng)來說是有一定優(yōu)勢(shì)的。
缺陷:首先是無差別的行為采集,這顯然增大了行為日志的數(shù)據(jù)體量,在上報(bào)中對(duì)流量的消耗很大,日志存儲(chǔ)成本也很高,而這巨大的損耗所帶來的信息價(jià)值呢?幾乎大部分都是鼠標(biāo)移動(dòng)或者滑輪滾動(dòng)的大量重復(fù)信息,無論是對(duì)業(yè)務(wù)分析還是錯(cuò)誤診斷都沒有太大貢獻(xiàn),甚至增加了分析問題的復(fù)雜性。
其次是行為日志的頻繁上報(bào),這對(duì)業(yè)務(wù)方來說可能也是不太友好的,性能監(jiān)控請(qǐng)求發(fā)的比本身的業(yè)務(wù)請(qǐng)求都多。
圖6. 行為日志全量上報(bào)
2)場(chǎng)景觸發(fā)上報(bào)
場(chǎng)景觸發(fā)上報(bào)即是指,當(dāng)符合一定條件或者場(chǎng)景時(shí)才上報(bào)行為日志,對(duì)于JS錯(cuò)誤診斷中的用戶行為回溯場(chǎng)景而言,當(dāng)然就是錯(cuò)誤觸發(fā)上報(bào),當(dāng)頁面監(jiān)聽到error時(shí),便把當(dāng)前采集到的行為列表伴隨error詳情一并上報(bào),作為錯(cuò)誤診斷的輔助信息。
行為日志伴隨錯(cuò)誤一起上報(bào)的方式需要維護(hù)一個(gè)行為隊(duì)列,隊(duì)列應(yīng)設(shè)有最大長(zhǎng)度,當(dāng)捕獲到j(luò)s error的時(shí)候,將行為隊(duì)列作為js錯(cuò)誤日志的一個(gè)補(bǔ)充信息一起上報(bào),圖7所示為sentry錯(cuò)誤日志上報(bào)的request payload,其用戶行為隊(duì)列包含在錯(cuò)誤日志的“breadcrumbs”字段中。
這種用戶行為伴隨錯(cuò)誤上報(bào)的方式就相對(duì)輕量很多,首先錯(cuò)誤和行為一起上報(bào)減少了請(qǐng)求數(shù)量;其次對(duì)用戶行為選擇性采集,避免了大量冗余信息對(duì)流量和存儲(chǔ)的消耗,就js錯(cuò)誤診斷而言會(huì)使得錯(cuò)誤現(xiàn)場(chǎng)變得更清晰,對(duì)分析錯(cuò)誤有利。
當(dāng)然這種行為上報(bào)的方式也是有不可忽視的問題,即行為和js error的強(qiáng)耦合,使得用戶行為信息失去了業(yè)務(wù)分析的擴(kuò)展性,僅適用于JS錯(cuò)誤診斷。
圖7. 行為日志breadcrumbs上報(bào)
三、用戶行為回溯在js錯(cuò)誤診斷中的應(yīng)用
圖8展示了Arms前端性能監(jiān)控的JS錯(cuò)誤診斷中用戶行為回溯的情況,在錯(cuò)誤詳情中復(fù)原出錯(cuò)現(xiàn)場(chǎng),輔助排查。下圖展示了用戶在進(jìn)行了“接口請(qǐng)求-控制臺(tái)輸出-點(diǎn)擊按鈕-控制臺(tái)輸出”的一系列行為后發(fā)生了JS錯(cuò)誤,即可從按鈕的點(diǎn)擊事件的處理函數(shù)中進(jìn)行錯(cuò)誤排查。
?
圖8. Arms前端性能監(jiān)控的用戶行為回溯
原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的应用实时监控 ARMS 上线用户行为回溯功能的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 刚刚,阿里巴巴小程序生态联盟重磅启动
- 下一篇: 使用阿里云极速型NAS构建高可用的Git