監控平臺前端SDK開發實踐

美團點評點餐發表於2017-08-16

作者簡介:楊婷,美團點評點餐終端團隊成員。

監控平臺

監控的重要性和必要性不必多說,這是提高故障處理能力和保障服務質量所必須的一環。
那麼監控究竟要做什麼呢?簡而言之:及時上報錯誤,收集有效資訊,提供故障排查依據。

  • 及時上報錯誤:相信每個程式設計師都有這樣的經驗,發生線上問題後,經由運營或者產品反饋到開發人員,其中流轉過程可能是幾分鐘甚至幾十分鐘,這段時間可能直接導致公司的經濟損失。如果有一個監控系統,線上上出現問題時,監控系統能夠第一時間報警,並且通知到開發人員,那開發人員就可以第一時間修復上線,直接可以使公司損失最小化。
  • 收集有效資訊:特別是移動時代,定位一個問題時,需要很多使用者資訊(如使用者手機版本,網路情況,操作流程等)。如果沒有監控資料,往往只能靠猜,又或是來回找產品運營甚至出現問題的使用者去溝通定位,其中不可避免的會花費大量的時間。但是如果監控系統裡記錄了裝置資訊,錯誤發生時的場景資訊,以及使用者的操作流等程,我們就可以直接根據這些資訊進行問題定位,在最短時間內完成故障修復,減小問題的影響面。
  • 提供故障排查依據:監控前端SDK所上報的錯誤資訊和其他的記錄資訊,其最終目的都是作為我們排查故障的依據,為我們保障服務提供堅實的依靠。

監控分類

所以我們監控平臺需要包括記錄型監控和捕捉型監控:

  • 記錄型監控
    • 頁面訪問記錄:使用者訪問了哪些頁面
    • 資源載入記錄:頁面中載入了哪些資源
    • 使用者行為記錄:使用者在頁面上做了哪些操作,目前我們只記錄使用者的點選行為
    • 介面呼叫相關記錄:頁面呼叫了哪些介面
  • 捕捉型監控
    • DNS劫持:頁面是否被劫持
    • 資源載入錯誤:哪些資源載入失敗了,為了捕獲跨域js的錯誤,需要在相應資源標籤上新增crossorigin屬性。
    • 頁面錯誤:頁面渲染過程中出現的錯誤
    • 內部邏輯錯誤:使用者特定操作出現的錯誤,通過使用者行為定位
    • 介面錯誤:呼叫介面失敗

場景還原法

場景還原是監控皮膚提供的一個非常有用的功能,它將支撐系統處理過的所有記錄和錯誤按照時間順序展示。通過場景還原的列表,我們可以還原出指定使用者在瀏覽頁面過程中發生的所有事情及其先後順序,從而判斷問題發生的時機和環境。

假設以下場景:

PM:BD反饋使用者在購物車刷不出來啦!
RD:什麼?我試試!我這裡可以看到的呀
PM:商戶反饋,店裡有的使用者可以有的使用者不行
RD:別急,告訴我shopId和打不開的使用者的賬號,我去監控平臺上看一下
PM:xxx
RD在監控皮膚上使用場景還原功能,調出了該使用者的所有資訊記錄。發現該使用者是從菜品詳情頁進入的購物車,而再檢視正常的使用者都不是從這個入口進的,定位到是菜品詳情頁跳購物車的部分有問題,並立刻進行了修復

在以上這種使用者可能有多種操作的場景中,場景還原法可以針對特定使用者,還原其完整的操作路徑和頁面上發生的所有事情,幫助復現問題。
另外,一些非必現的問題,常常是由於不同機型或環境引起的,也可以在場景還原中復現問題的發生環境予以判斷。


監控平臺總體分為三部分:

  • 監控前端SDK:收集使用者端錯誤和相關資訊,並進行上報
  • 監控web層支撐系統:處理上報的監控資訊
  • 監控皮膚:提供實時檢視上報資訊的皮膚,方便監控資料的便捷使用

本文主要介紹監控前端SDK的實踐經驗,仍有許多需要改進的地方,歡迎大家拍磚,幫助我們改進。

整體設計


如圖所示,整個監控平臺分為前端SDK、web層支撐系統和監控皮膚三大部分,前端SDK執行在前端頁面中,收集監控資料上報到支撐系統裡,作為監控皮膚上查詢的資料來源。

就前端SDK來說,可以分為資料模組、資料處理模組、上報模組三大部分,其中資料模組包括各具體監控資料模組和環境資料模組:

  • 資料模組
    • 各監控模組:獲取需要上報的具體內容資訊(EventData或ErrorData)
      • DNS劫持檢測
      • 資源完整性檢查
      • 資源載入錯誤
      • API監控
      • 全域性錯誤
      • 使用者互動
      • 自定義上報
    • 環境模組:獲取環境資料
  • 資料處理模組:將環境資料和各內容資料,處理成介面對應的格式,並返回標準格式資料
  • 上報模組:從環境模組獲取環境資料,再和內容資料一起根據不同監控型別分發到對應的資料處理模組。獲取標準資料後傳送到node層。
    上報模組先檢視本地快取資料,將本地資料和新產生的資料一起上報,若上報失敗則存入localStorage

詳細設計

SDK裡採用單例模式,包括各監控模組、環境模組和上報模組。
每個具體監控模組獲取上報模組例項進行上報,上報模組內部保證同時只會有一個上報請求。
事件的監聽都在捕獲階段進行,防止因為事件冒泡被阻止而遺漏資訊。

環境模組

環境模組收集以下環境資訊:專案配置資訊、web環境資料、jsbridge環境資料
其他的一些諸如UA、isp等web層可以獲取的資訊由web層獲取。
該模組暴露init和getEnv方法

  • init接收使用者配置的環境引數
  • getEnv更新頁面url,再返回當前env物件freeze的一個副本

上報模組

採取單請求上報的方式,每個使用者同時只會有一條上報請求,每次將當前記錄到的監控資訊列表一起上報,成功後再繼續上報。

上報結束之前的新上報記錄都存在localstorage,收到成功訊息後刪除已上報資料,繼續上報,不成功的記錄保留在localstorage。此處需注意對localstorage儲存的上限做好控制。

在當前沒有資料正在上報的情況下觸發上報,嘗試將當前localstorage的資料和新資料全部上報,若上報記錄過多,則分條傳送。全部傳送完或上報失敗,本次上報結束。

各具體監控模組

DNS劫持

HTTPS頁面被劫持後頁面資源無法獲取,劫持者無利可圖的情況下會降低劫持的動力。
若仍被劫持,前端資源未到達本地,也無法完成上報,只能從網路層去監控。
由於我司已經全量切了HTTPS,因此該模組不在本監控系統中。
不過之前本團隊做過對HTTP域下的劫持檢測,其檢測思路為請求Node層指定域名下的樣本HTML或JS資源,對比返回結果是否符合預期。

資源完整性檢查

資源完整性檢查模組的任務是記錄頁面載入了哪些資源,並進行上報。
當我們排查問題時,可以檢視當前頁面已經載入成功了哪些資源及其載入順序,排除因為某些資源沒有載入或者載入順序不當而引起錯誤的情況。


資源載入完整性檢查的上報時機分四類,每次將開始監聽到觸發上報之間所有記錄到的已載入資源一起上報,減少上報請求數:

  1. onload:window.onload時觸發
  2. onload_timeout: onload超時(5秒)時觸發
  3. async:window.onload後一定延時(5秒)觸發,上報後停止監聽
  4. hash_change:onhashchange開始監聽,一定延時(5秒)觸發上報,上報後停止監聽

記憶體中維護一個已載入資源的陣列,每次上報後刪除已上報的資源記錄。

資源載入錯誤監控

window上error事件代理,過濾window本身的error
根據標籤型別判斷資源型別,src或href為資源地址
為了捕獲跨域js的錯誤,需要在相應資源標籤上新增crossorigin屬性。

API錯誤監控

同樣採用XMLHttpRequest加hook方式實現。
open時記錄介面url,send後根據status判斷,介面呼叫失敗時進行上報。

XMLHttpRequest.prototype.open = function open(method, url, bool) {
    monitor.originXHR.open.apply(this, [method, url, bool]);
    // get something...
    // this.ajaxUrl = url;
}

XMLHttpRequest.prototype.send = function send(_data) {
    const self = this;

    this.addEventListener('readystatechange', () => {
        if (self.readyState === 4) {
            if (self.status !== 200 && self.status !== 304 && this.ajaxUrl !== REPORT_URL) { // filter urls
                // report error info
                // ...
                // monitor.reporter.report(dataTypes.API_ERROR, error);
            }
        }
    }, false);

    monitor.originXHR.send.apply(this, [_data]);
};複製程式碼

過濾掉sdk本身的上報地址(防止上報失敗引起迴圈上報)和一些其他需要忽略的介面地址。

敲黑板,介面訪問url時可能是一個相對路徑,建議補全協議和domain

全域性錯誤監控

監聽window上的error事件,過濾事件代理的error。

使用者互動監控

監聽window上捕獲階段的click事件,記錄點選相關資料。

業務程式碼中可以為比較關注的元素新增data屬性,每次點選將會上報被點選元素的指定屬性、附加資訊和domPath幫助定位該元素。

記錄使用者互動資訊可以明確問題發生時,該場景下使用者的具體操作路徑,結合環境資料、資源載入記錄和錯誤資料,整個問題場景就一目瞭然了。

接入方式

sdk的接入方式分為以下兩種:

  1. 先載入sdk
    • 優點:可以記錄頁面載入完成前的情況,載入的資源,以及發生的錯誤
    • 缺點:影響頁面載入速度,直接拷貝在head中,對業務接入不友好
  2. 後載入sdk
    • 優點:不影響頁面效能
    • 缺點:只能監控載入成功的頁面,但我們需要關心頁面載入失敗的場景

為了滿足功能需要,當前監控平臺v1的引入方式是將壓縮後的sdk程式碼直接引入到被監控頁面的head中,並由業務程式碼初始化配置專案名稱等。該步操作可以藉助webpack的外掛來幫助完成,減輕業務組接入的複雜度。

後續改進方向考慮採用:核心基礎庫+loaders/plugins 的方式,將必須先載入的sdk程式碼引入在head中,其餘程式碼等頁面載入完成後再非同步新增。

以上就是我們終端團隊監控平臺前端SDK部分的實踐分享啦,歡迎大家批評指正,有好的建議也希望能提出來幫助我們改進。我們後續將不斷優化,也將繼續與大家保持討論。耐心看到這裡的讀者,表示十二萬分的感謝~~

相關文章