前端異常監控解決方案研究

摘要: 異常監控不復雜也不簡單啊...前端

前端監控包括行爲監控、異常監控、性能監控等,本文主要討論異常監控。對於前端而言,和後端處於同一個監控系統中,前端有本身的監控方案,後端也有本身等監控方案,但二者並不分離,由於一個用戶在操做應用過程當中若是出現異常,有多是前端引發,也有多是後端引發,須要有一個機制,將先後端串聯起來,使監控自己統一於監控系統。所以,即便只討論前端異常監控,其實也不能嚴格區分先後端界限,而要根據實際系統的設計,在最終的報表中體現出監控對開發和業務的幫助。vue

通常而言,一個監控系統,大體能夠分爲四個階段:日誌採集、日誌存儲、統計與分析、報告和警告。react

採集階段:收集異常日誌,先在本地作必定的處理,採起必定的方案上報到服務器。git

存儲階段:後端接收前端上報的異常日誌,通過必定處理,按照必定的存儲方案存儲。web

分析階段:分爲機器自動分析和人工分析。機器自動分析,經過預設的條件和算法,對存儲的日誌信息進行統計和篩選,發現問題,觸發報警。人工分析,經過提供一個可視化的數據面板,讓系統用戶能夠看到具體的日誌數據,根據信息,發現異常問題根源。算法

報警階段:分爲告警和預警。告警按照必定的級別自動報警,經過設定的渠道,按照必定的觸發規則進行。預警則在異常發生前,提早預判,給出警告。數據庫

1 前端異常

前端異常是指在用戶使用Web應用時沒法快速獲得符合預期結果的狀況,不一樣的異常帶來的後果程度不一樣,輕則引發用戶使用不悅,重則致使產品沒法使用,使用戶喪失對產品的承認。編程

1.1 前端異常分類

根據異常代碼的後果的程度,對前端異常的表現分爲以下幾類小程序

a. 出錯後端

界面呈現的內容與用戶預期的內容不符,例如點擊進入非目標界面,數據不許確,出現的錯誤提示不可理解,界面錯位,提交後跳轉到錯誤界面等狀況。這類異常出現時,雖然產品自己功能還能正常使用,但用戶沒法達成本身目標。

b. 呆滯

界面出現操做後沒有反應的現象,例如點擊按鈕沒法提交,提示成功後沒法繼續操做。這類異常出現時,產品已經存在界面級局部不可用現象。

c. 損壞

界面出現沒法實現操做目的的現象,例如點擊沒法進入目標界面,點擊沒法查看詳情內容等。這類異常出現時,應用部分功能沒法被正常使用。

d. 假死

界面出現卡頓,沒法對任何功能進行使用的現象。例如用戶沒法登錄致使沒法使用應用內功能,因爲某個遮罩層阻擋且不可關閉致使沒法進行任何後續操做。這類異常出現時,用戶極可能殺死應用。

e. 崩潰

應用出現常常性自動退出或沒法操做的現象。例如間歇性crash,網頁沒法正常加載或加載後沒法進行任何操做。這類異常持續出現,將直接致使用戶流失,影響產品生命力。

1.2 異常錯誤緣由分類

前端產生異常的緣由主要分5類:

緣由 案例 頻率
邏輯錯誤 1) 業務邏輯判斷條件錯誤 2) 事件綁定順序錯誤 3) 調用棧時序錯誤 4) 錯誤的操做js對象 常常
數據類型錯誤 1) 將null視做對象讀取property 2) 將undefined視做數組進行遍歷 3) 將字符串形式的數字直接用於加運算 4) 函數參數未傳 常常
語法句法錯誤 較少
網絡錯誤 1) 慢 2) 服務端未返回數據但仍200,前端按正常進行數據遍歷 3) 提交數據時網絡中斷 4) 服務端500錯誤時前端未作任何錯誤處理 偶爾
系統錯誤 1) 內存不夠用 2) 磁盤塞滿 3) 殼不支持API 4) 不兼容 較少

2 異常採集

2.1 採集內容

當異常出現的時候,咱們須要知道異常的具體信息,根據異常的具體信息來決定採用什麼樣的解決方案。在採集異常信息時,能夠遵循4W原則:

WHO did WHAT and get WHICH exception in WHICH environment?

a. 用戶信息

出現異常時該用戶的信息,例如該用戶在當前時刻的狀態、權限等,以及須要區分用戶可多終端登陸時,異常對應的是哪個終端。

b. 行爲信息

用戶進行什麼操做時產生了異常:所在的界面路徑;執行了什麼操做;操做時使用了哪些數據;當時的API吐了什麼數據給客戶端;若是是提交操做,提交了什麼數據;上一個路徑;上一個行爲日誌記錄ID等。

c. 異常信息

產生異常的代碼信息:用戶操做的DOM元素節點;異常級別;異常類型;異常描述;代碼stack信息等。

d. 環境信息

網絡環境;設備型號和標識碼;操做系統版本;客戶端版本;API接口版本等。

字段 類型 解釋
requestId String 一個界面產生一個requestId
traceId String 一個階段產生一個traceId,用於追蹤和一個異常相關的全部日誌記錄
hash String 這條log的惟一標識碼,至關於logId,但它是根據當前日誌記錄的具體內容而生成的
time Number 當前日誌產生的時間(保存時刻)
userId String
userStatus Number 當時,用戶狀態信息(是否可用/禁用)
userRoles Array 當時,前用戶的角色列表
userGroups Array 當時,用戶當前所在組,組別權限可能影響結果
userLicenses Array 當時,許可證,可能過時
path String 所在路徑,URL
action String 進行了什麼操做
referer String 上一個路徑,來源URL
prevAction String 上一個操做
data Object 當前界面的state、data
dataSources Array<Object> 上游api給了什麼數據
dataSend Object 提交了什麼數據
targetElement HTMLElement 用戶操做的DOM元素
targetDOMPath Array<HTMLElement> 該DOM元素的節點路徑
targetCSS Object 該元素的自定義樣式表
targetAttrs Object 該元素當前的屬性及值
errorType String 錯誤類型
errorLevel String 異常級別
errorStack String 錯誤stack信息
errorFilename String 出錯文件
errorLineNo Number 出錯行
errorColNo Number 出錯列位置
errorMessage String 錯誤描述(開發者定義)
errorTimeStamp Number 時間戳
eventType String 事件類型
pageX Number 事件x軸座標
pageY Number 事件y軸座標
screenX Number 事件x軸座標
screenY Number 事件y軸座標
pageW Number 頁面寬度
pageH Number 頁面高度
screenW Number 屏幕寬度
screenH Number 屏幕高度
eventKey String 觸發事件的鍵
network String 網絡環境描述
userAgent String 客戶端描述
device String 設備描述
system String 操做系統描述
appVersion String 應用版本
apiVersion String 接口版本

這是一份很是龐大的日誌字段表,它幾乎囊括了一個異常發生時,可以對異常周遭環境進行詳細描述的全部信息。不一樣狀況下,這些字段並不必定都會收集,因爲咱們會採用文檔數據庫存儲日誌,所以,並不影響它的實際存儲結果。

2.2 異常捕獲

前端捕獲異常分爲全局捕獲和單點捕獲。全局捕獲代碼集中,易於管理;單點捕獲做爲補充,對某些特殊狀況進行捕獲,但分散,不利於管理。

a、全局捕獲

經過全局的接口,將捕獲代碼集中寫在一個地方,能夠利用的接口有:

  • window.addEventListener(‘error’) / window.addEventListener(「unhandledrejection」) / document.addEventListener(‘click’) 等
  • 框架級別的全局監聽,例如aixos中使用interceptor進行攔截,vue、react都有本身的錯誤採集接口
  • 經過對全局函數進行封裝包裹,實如今在調用該函數時自動捕獲異常
  • 對實例方法重寫(Patch),在原有功能基礎上包裹一層,例如對console.error進行重寫,在使用方法不變的狀況下也能夠異常捕獲

b、單點捕獲

在業務代碼中對單個代碼塊進行包裹,或在邏輯流程中打點,實現有針對性的異常捕獲:

  • try…catch
  • 專門寫一個函數來收集異常信息,在異常發生時,調用該函數
  • 專門寫一個函數來包裹其餘函數,獲得一個新函數,該新函數運行結果和原函數如出一轍,只是在發生異常時能夠捕獲異常

2.3 跨域腳本異常

因爲瀏覽器安全策略限制,跨域腳本報錯時,沒法直接獲取錯誤的詳細信息,只能獲得一個Script Error。例如,咱們會引入第三方依賴,或者將本身的腳本放在CDN時。

解決Script Error的方法:

方案一:

  • 將js內聯到HTML中
  • 將js文件與HTML放在同域下

方案二:

  1. 爲頁面上script標籤添加crossorigin屬性
  2. 被引入腳本所在服務端響應頭中,增長 Access-Control-Allow-Origin 來支持跨域資源共享

2.4 異常錄製

對於一個異常,僅僅擁有該異常的信息還不足以徹底抓住問題的本質,由於異常發生的位置,並不必定是異常根源所在的位置。咱們須要對異常現場進行還原,才能復原問題全貌,甚至避免相似問題在其餘界面中發生。這裏須要引進一個概念,就是「異常錄製」。錄製經過「時間」「空間」兩個維度記錄異常發生前到發生的整個過程,對於找到異常根源更有幫助。

上圖表示,當異常發生時,異常的根源可能離咱們很遠,咱們須要回到異常發生的現場,找到異常根源。就像現實生活中破案同樣,若是有監控攝影機對案發過程的錄影,對破案來講更加容易。若是僅僅關注異常自己,要找到異常的根源,須要憑藉運氣,但有了異常錄製的幫助,找到根源就更加容易。

所謂的「異常錄製」,實際上就是經過技術手段,收集用戶的操做過程,對用戶的每個操做都進行記錄,在發生異常時,把必定時間區間內的記錄從新運行,造成影像進行播放,讓調試者無需向用戶詢問,就能看到用戶當時的操做過程。

上圖是來自阿里的一套異常錄製還原方案示意圖,用戶在界面上的操做產生的events和mutation被產品收集起來,上傳到服務器,通過隊列處理按順序存放到數據庫中。當須要進行異常重現的時候,將這些記錄從數據庫中取出,採用必定的技術方案,順序播放這些記錄,便可實現異常還原。

2.5 異常級別

通常而言,咱們會將收集信息的級別分爲info,warn,error等,並在此基礎上進行擴展。

當咱們監控到異常發生時,能夠將該異常劃分到「重要——緊急」模型中分爲A、B、C、D四個等級。有些異常,雖然發生了,可是並不影響用戶的正常使用,用戶其實並無感知到,雖然理論上應該修復,可是實際上相對於其餘異常而言,能夠放在後面進行處理。

下文會討論告警策略,通常而言,越靠近右上角的異常會越快通知,保證相關人員能最快接收到信息,並進行處理。A級異常須要快速響應,甚至須要相關負責人知悉。

在收集異常階段,可根據第一節劃分的異常後果來判斷異常的嚴重程度,在發生異常時選擇對應的上報方案進行上報。

3 整理與上報方案

前文已經提到,除了異常報錯信息自己,咱們還須要記錄用戶操做日誌,以實現場景復原。這就涉及到上報的量和頻率問題。若是任何日誌都當即上報,這無異於自造的DDOS攻擊。所以,咱們須要合理的上報方案。下文會介紹4種上報方案,但實際咱們不會僅限於其中一種,而是常常同時使用,對不一樣級別的日誌選擇不一樣的上報方案。

3.1 前端存儲日誌

咱們前面提到,咱們並不僅僅採集異常自己日誌,並且還會採集與異常相關的用戶行爲日誌。單純一條異常日誌並不能幫助咱們快速定位問題根源,找到解決方案。但若是要收集用戶的行爲日誌,又要採起必定的技巧,而不能用戶每個操做後,就當即將該行爲日誌傳到服務器,對於具備大量用戶同時在線的應用,若是用戶一操做就當即上傳日誌,無異於對日誌服務器進行DDOS攻擊。所以,咱們先將這些日誌存儲在用戶客戶端本地,達到必定條件以後,再同時打包上傳一組日誌。

那麼,如何進行前端日誌存儲呢?咱們不可能直接將這些日誌用一個變量保存起來,這樣會擠爆內存,並且一旦用戶進行刷新操做,這些日誌就丟失了,所以,咱們天然而然想到前端數據持久化方案。

目前,可用的持久化方案可選項也比較多了,主要有:Cookie、localStorage、sessionStorage、IndexedDB、webSQL 、FileSystem 等等。那麼該如何選擇呢?咱們經過一個表來進行對比:

存儲方式 cookie localStorage sessionStorage IndexedDB webSQL FileSystem
類型 key-value key-value NoSQL SQL
數據格式 string string string object
容量 4k 5M 5M 500M 60M
進程 同步 同步 同步 異步 異步
檢索 key key key, index field
性能 讀快寫慢 讀慢寫快

綜合以後,IndexedDB是最好的選擇,它具備容量大、異步的優點,異步的特性保證它不會對界面的渲染產生阻塞。並且IndexedDB是分庫的,每一個庫又分store,還能按照索引進行查詢,具備完整的數據庫管理思惟,比localStorage更適合作結構化數據管理。可是它有一個缺點,就是api很是複雜,不像localStorage那麼簡單直接。針對這一點,咱們可使用hello-indexeddb這個工具,它用Promise對複雜api進行來封裝,簡化操做,使IndexedDB的使用也能作到localStorage同樣便捷。另外,IndexedDB是被普遍支持的HTML5標準,兼容大部分瀏覽器,所以不用擔憂它的發展前景。

接下來,咱們究竟應該怎麼合理使用IndexedDB,保證咱們前端存儲的合理性呢?

上圖展現了前端存儲日誌的流程和數據庫佈局。當一個事件、變更、異常被捕獲以後,造成一條初始日誌,被當即放入暫存區(indexedDB的一個store),以後主程序就結束了收集過程,後續的事只在webworker中發生。在一個webworker中,一個循環任務不斷從暫存區中取出日誌,對日誌進行分類,將分類結果存儲到索引區中,並對日誌記錄的信息進行豐富,將最終將會上報到服務端的日誌記錄轉存到歸檔區。而當一條日誌在歸檔區中存在的時間超過必定天數以後,它就已經沒有價值了,可是爲了防止特殊狀況,它被轉存到回收區,再經歷一段時間後,就會被從回收區中清除。

3.2 前端整理日誌

上文講到,在一個webworker中對日誌進行整理後存到索引區和歸檔區,那麼這個整理過程是怎樣的呢?

因爲咱們下文要講的上報,是按照索引進行的,所以,咱們在前端的日誌整理工做,主要就是根據日誌特徵,整理出不一樣的索引。咱們在收集日誌時,會給每一條日誌打上一個type,以此進行分類,並建立索引,同時經過object-hashcode計算每一個log對象的hash值,做爲這個log的惟一標誌。

  • 將全部日誌記錄按時序存放在歸檔區,並將新入庫的日誌加入索引
  • BatchIndexes:批量上報索引(包含性能等其餘日誌),可一次批量上報100條
  • MomentIndexes:即時上報索引,一次所有上報
  • FeedbackIndexes:用戶反饋索引,一次上報一條
  • BlockIndexes:區塊上報索引,按異常/錯誤(traceId,requestId)分塊,一次上報一塊
  • 上報完成後,被上報過的日誌對應的索引刪除
  • 3天以上日誌進入回收區
  • 7天以上的日誌從回收區清除

rquestId:同時追蹤先後端日誌。因爲後端也會記錄本身的日誌,所以,在前端請求api的時候,默認帶上requestId,後端記錄的日誌就能夠和前端日誌對應起來。

traceId:追蹤一個異常發生先後的相關日誌。當應用啓動時,建立一個traceId,直到一個異常發生時,刷新traceId。把一個traceId相關的requestId收集起來,把這些requestId相關的日誌組合起來,就是最終這個異常相關的全部日誌,用來對異常進行復盤。

上圖舉例展現瞭如何利用traceId和requestId找出和一個異常相關的全部日誌。在上圖中,hash4是一條異常日誌,咱們找到hash4對應的traceId爲traceId2,在日誌列表中,有兩條記錄具備該traceId,可是hash3這條記錄並非一個動做的開始,由於hash3對應的requestId爲reqId2,而reqId2開始於hash2,所以,咱們實際上要把hash2也加入到該異常發生的整個覆盤備選記錄中。總結起來就是,咱們要找出同一個traceId對應的全部requestId對應的日誌記錄,雖然有點繞,但稍理解就能夠明白其中的道理。

咱們把這些和一個異常相關的全部日誌集合起來,稱爲一個block,再利用日誌的hash集合,得出這個block的hash,並在索引區中創建索引,等待上報。

3.3 上報日誌

上報日誌也在webworker中進行,爲了和整理區分,能夠分兩個worker。上報的流程大體爲:在每個循環中,從索引區取出對應條數的索引,經過索引中的hash,到歸檔區取出完整的日誌記錄,再上傳到服務器。

按照上報的頻率(重要緊急度)可將上報分爲四種:

a. 即時上報

收集到日誌後,當即觸發上報函數。僅用於A類異常。並且因爲受到網絡不肯定因素影響,A類日誌上報須要有一個確認機制,只有確認服務端已經成功接收到該上報信息以後,纔算完成。不然須要有一個循環機制,確保上報成功。

b. 批量上報

將收集到的日誌存儲在本地,當收集到必定數量以後再打包一次性上報,或者按照必定的頻率(時間間隔)打包上傳。這至關於把屢次合併爲一次上報,以下降對服務器的壓力。

c. 區塊上報

將一次異常的場景打包爲一個區塊後進行上報。它和批量上報不一樣,批量上報保證了日誌的完整性,全面性,但會有無用信息。而區塊上報則是針對異常自己的,確保單個異常相關的日誌被所有上報。

d. 用戶主動提交

在界面上提供一個按鈕,用戶主動反饋bug。這有利於增強與用戶的互動。

或者當異常發生時,雖然對用戶沒有任何影響,可是應用監控到了,彈出一個提示框,讓用戶選擇是否願意上傳日誌。這種方案適合涉及用戶隱私數據時。

即時上報 批量上報 區塊上報 用戶反饋
時效 當即 定時 稍延時 延時
條數 一次所有上報 一次100條 單次上報相關條目 一次1條
容量
緊急 緊急重要 不緊急 不緊急但重要 不緊急

即時上報雖然叫即時,可是其實也是經過相似隊列的循環任務去完成的,它主要是儘快把一些重要的異常提交給監控系統,好讓運維人員發現問題,所以,它對應的緊急程度比較高。

批量上報和區塊上報的區別:批量上報是一次上報必定條數,好比每2分鐘上報1000條,直到上報完成。而區塊上報是在異常發生以後,立刻收集和異常相關的全部日誌,查詢出哪些日誌已經由批量上報上報過了,剔除掉,把其餘相關日誌上傳,和異常相關的這些日誌相對而言更重要一些,它們能夠幫助儘快復原異常現場,找出發生異常的根源。

用戶提交的反饋信息,則能夠慢悠悠上報上去。

爲了確保上報是成功的,在上報時須要有一個確認機制,因爲在服務端接收到上報日誌以後,並不會當即存入數據庫,而是放到一個隊列中,所以,先後端在確保日誌確實已經記錄進數據庫這一點上須要再作一些處理。

上圖展現了上報的一個大體流程,在上報時,先經過hash查詢,讓客戶端知道準備要上報的日誌集合中,是否存在已經被服務端保存好的日誌,若是已經存在,就將這些日誌去除,避免重複上報,浪費流量。

3.4 壓縮上報數據

一次性上傳批量數據時,必然遇到數據量大,浪費流量,或者傳輸慢等狀況,網絡很差的狀態下,可能致使上報失敗。所以,在上報以前進行數據壓縮也是一種方案。

對於合併上報這種狀況,一次的數據量可能要十幾k,對於日 pv 大的站點來講,產生的流量仍是很可觀的。因此有必要對數據進行壓縮上報。lz-string是一個很是優秀的字符串壓縮類庫,兼容性好,代碼量少,壓縮比高,壓縮時間短,壓縮率達到驚人的60%。但它基於LZ78壓縮,若是後端不支持解壓,可選擇gzip壓縮,通常而言後端會默認預裝gzip,所以,選擇gzip壓縮數據也能夠,工具包pako中自帶了gzip壓縮,能夠嘗試使用。

4 日誌接收與存儲

4.1 接入層與消息隊列

通常經過提供獨立的日誌服務器接收客戶端日誌,接收過程當中,要對客戶端日誌內容的合法性、安全性等進行甄別,防止被人攻擊。並且因爲日誌提交通常都比較頻繁,多客戶端同時併發的狀況也常見。經過消息隊列將日誌信息逐一處理後寫入到數據庫進行保存也是比較經常使用的方案。

上圖爲騰訊BetterJS的架構圖,其中「接入層」和「推送中心」就是這裏提到的接入層和消息隊列。BetterJS將整個前端監控的各個模塊進行拆分,推送中心承擔了將日誌推送到存儲中心進行存儲和推送給其餘系統(例如告警系統)的角色,但咱們能夠把接收日誌階段的隊列獨立出來看,在接入層和存儲層之間作一個過渡。

4.2 日誌存儲系統

存儲日誌是一個髒活累活,可是不得不作。對於小應用,單庫單表加優化就能夠應付。一個成規模的應用,若是要提供更標準高效的日誌監控服務,經常須要在日誌存儲架構上下一些功夫。目前業界已經有比較完備的日誌存儲方案,主要有:Hbase系,Dremel系,Lucene系等。整體而言,日誌存儲系統主要面對的問題是數據量大,數據結構不規律,寫入併發高,查詢需求大等。通常一套日誌存儲系統,要解決上面這些問題,就要解決寫入的緩衝,存儲介質按日誌時間選擇,爲方便快速讀取而設計合理的索引系統等等。

因爲日誌存儲系統方案比較成熟,這裏就再也不作更多討論。

4.3 搜索

日誌的最終目的是要使用,因爲通常日誌的體量都很是大,所以,要在龐大的數據中找到須要的日誌記錄,須要依賴比較好的搜索引擎。Splunk是一套成熟的日誌存儲系統,但它是付費使用的。按照Splunk的框架,Elk是Splunk的開源實現,Elk是ElasticSearch、Logstash、Kibana的結合,ES基於Lucene的存儲、索引的搜索引擎;logstash是提供輸入輸出及轉化處理插件的日誌標準化管道;Kibana提供可視化和查詢統計的用戶界面。

5 日誌統計與分析

一個完善的日誌統計分析工具須要提供各方面方便的面板,以可視化的方式給日誌管理員和開發者反饋信息。

5.1 用戶緯度

同一個用戶的不一樣請求實際上會造成不一樣的story線,所以,針對用戶的一系列操做設計惟一的request id是有必要的。同一個用戶在不一樣終端進行操做時,也能進行區分。用戶在進行某個操做時的狀態、權限等信息,也須要在日誌系統中予以反應。

5.2 時間維度

一個異常是怎麼發生的,須要將異常操做的先後story線串聯起來觀察。它不僅僅涉及一個用戶的一次操做,甚至不限於某一個頁面,而是一連串事件的最終結果。

5.3 性能維度

應用運行過程當中的性能狀況,例如,界面加載時間,api請求時長統計,單元計算的消耗,用戶呆滯時間。

5.4 運行環境維度

應用及服務所運行的環境狀況,例如應用所在的網絡環境,操做系統,設備硬件信息等,服務器cpu、內存情況,網絡、寬帶使用狀況等。

5.5 細粒度代碼追蹤

異常的代碼stack信息,定位到發生異常的代碼位置和異常堆棧。

5.6 場景回溯

經過將異常相關的用戶日誌鏈接起來,以動態的效果輸出發生異常的過程。

6 監控與通知

對異常進行統計和分析只是基礎,而在發現異常時能夠推送和告警,甚至作到自動處理,纔是一個異常監控系統應該具有的能力。

6.1 自定義觸發條件的告警

a. 監控實現

當日志信息進入接入層時,就能夠觸發監控邏輯。當日志信息中存在較爲高級別的異常時,也能夠當即出發告警。告警消息隊列和日誌入庫隊列能夠分開來管理,實現並行。

對入庫日誌信息進行統計,對異常信息進行告警。對監控異常進行響應。所謂監控異常,是指:有規律的異常通常而言都比較讓人放心,比較麻煩的是忽然之間的異常。例如在某一時段忽然頻繁接收到D級異常,雖然D級異常是不緊急通常重要,可是當監控自己發生異常時,就要提升警戒。

b. 自定義觸發條件

除了系統開發時配置的默認告警條件,還應該提供給日誌管理員可配置的自定義觸發條件。

  • 日誌內含有什麼內容時
  • 日誌統計達到什麼度、量時
  • 向符合什麼條件的用戶告警

6.2 推送渠道

可選擇的途徑有不少,例如郵件、短信、微信、電話。

6.3 推送頻率

針對不一樣級別的告警,推送的頻率也能夠進行設定。低風險告警能夠以報告的形式一天推送一次,高風險告警10分鐘循環推送,直處處理人手動關閉告警開關。

6.4 自動報表

對於日誌統計信息的推送,能夠作到自動生成日報、週報、月報、年報並郵件發送給相關羣組。

6.5 自動產生bug工單

當異常發生時,系統能夠調用工單系統API實現自動生成bug單,工單關閉後反饋給監控系統,造成對異常處理的追蹤信息進行記錄,在報告中予以展現。

7 修復異常

7.1 sourcemap

前端代碼大部分狀況都是通過壓縮後發佈的,上報的stack信息須要還原爲源碼信息,才能快速定位源碼進行修改。

發佈時,只部署js腳本到服務器上,將sourcemap文件上傳到監控系統,在監控系統中展現stack信息時,利用sourcemap文件對stack信息進行解碼,獲得源碼中的具體信息。

可是這裏有一個問題,就是sourcemap必須和正式環境的版本對應,還必須和git中的某個commit節點對應,這樣才能保證在查異常的時候能夠正確利用stack信息,找到出問題所在版本的代碼。這些能夠經過創建CI任務,在集成化部署中增長一個部署流程,以實現這一環節。

7.2 從告警到預警

預警的本質是,預設可能出現異常的條件,當觸發該條件時異常並無真實發生,所以,能夠趕在異常發生以前對用戶行爲進行檢查,及時修復,避免異常或異常擴大。

怎麼作呢?其實就是一個統計聚類的過程。將歷史中發生異常的狀況進行統計,從時間、地域、用戶等不一樣維度加以統計,找出規律,並將這些規律經過算法自動加入到預警條件中,當下次觸發時,及時預警。

7.3 智能修復

自動修復錯誤。例如,前端要求接口返回數值,但接口返回了數值型的字符串,那麼能夠有一種機制,監控系統發送正確數據類型模型給後端,後端在返回數據時,根據該模型控制每一個字段的類型。

8 異常測試

8.1 主動異常測試

撰寫異經常使用例,在自動化測試系統中,加入異常測試用戶。在測試或運行過程當中,每發現一個異常,就將它加入到原有的異經常使用例列表中。

8.2 隨機異常測試

模擬真實環境,在模擬器中模擬真實用戶的隨機操做,利用自動化腳本產生隨機操做動做代碼,並執行。

定義異常,例如彈出某個彈出框,包含特定內容時,就是異常。將這些測試結果記錄下來,再聚類統計分析,對防護異常也頗有幫助。

9 部署

9.1 多客戶端

一個用戶在不一樣終端上登陸,或者一個用戶在登陸前和登陸後的狀態。經過特定算法生成requestID,經過該requestId能夠肯定某個用戶在獨立客戶端上的一系列操做,根據日誌時序,能夠梳理出用戶產生異常的具體路徑。

9.2 集成便捷性

前端寫成包,全局引用便可完成大部分日誌記錄、存儲和上報。在特殊邏輯裏面,能夠調用特定方法記錄日誌。

後端與應用自己的業務代碼解耦,能夠作成獨立的服務,經過接口和第三方應用交互。利用集成部署,能夠將系統隨時進行擴容、移植等操做。

9.3 管理系統的可擴展

整套系統可擴展,不只服務單應用,可支持多個應用同時運行。同一個團隊下的全部應用均可以利用同一個平臺進行管理。

9.4 日誌系統權限

不一樣的人在訪問日誌系統時權限不一樣,一個訪問者只能查看本身相關的應用,有些統計數據若是比較敏感,能夠單獨設置權限,敏感數據可脫敏。

10 其餘

10.1 性能監控

異常監控主要針對代碼級別的報錯,但也應該關注性能異常。性能監控主要包括:

  • 運行時性能:文件級、模塊級、函數級、算法級
  • 網絡請求速率
  • 系統性能

10.2 API Monitor

後端API對前端的影響也很是大,雖然前端代碼也控制邏輯,可是後端返回的數據是基礎,所以對API的監控能夠分爲:

  • 穩定性監控
  • 數據格式和類型
  • 報錯監控
  • 數據準確性監控

10.3 數據脫敏

敏感數據不被日誌系統採集。因爲日誌系統的保存是比較開放的,雖然裏面的數據很重要,可是在存儲上大部分日誌系統都不是保密級,所以,若是應用涉及了敏感數據,最好作到:

  • 獨立部署,不和其餘應用共享監控系統
  • 不採集具體數據,只採集用戶操做數據,在重現時,經過日誌信息能夠取出數據api結果來展現
  • 日誌加密,作到軟硬件層面的加密防禦
  • 必要時,可採集具體數據的ID用於調試,場景重現時,用mock數據替代,mock數據可由後端採用假的數據源生成
  • 對敏感數據進行混淆

結語

本文主要是對前端異常監控的總體框架進行了研究,沒有涉及到具體的技術實現,涉及前端部分和後臺部分以及與整個問題相關的一些知識點,主要關注前端部分,它和後端的監控有重疊部分也有分支部分,須要在一個項目中不斷實踐,總結出項目自己的監控需求和策略。

感謝你的閱讀,本文出自 Tencent CDC,轉載時請註明出處,謝謝合做。 格式爲:Tencent CDC(https://cdc.tencent.com/2018/09/13/frontend-exception-monitor-research/)

關於Fundebug

Fundebug專一於JavaScript、微信小程序、微信小遊戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了20億+錯誤事件,付費客戶有陽光保險、核桃編程、荔枝FM、掌門1對一、微脈、青團社等衆多品牌企業。歡迎你們免費試用

相關文章
相關標籤/搜索