從無到有<前端異常監(jiān)控系統(tǒng)>落地

導火索

有一天一個測試同事的一個移動端頁面白屏了,看樣子是頁面哪里報錯了目溉。? 我自己打開頁面并沒有報錯明肮,最后發(fā)現(xiàn)報錯只存在于他的手機,移動端項目又是在微信環(huán)境下缭付,調(diào)試起來會比較麻煩柿估,最后用他手機調(diào)試才發(fā)現(xiàn)問題: 是他賬戶下面有個對話的消息數(shù)據(jù)有問題導致頁面報錯了。? 一般遇到這種情況只有用他的手機或者賬戶調(diào)試能很快查到問題陷猫,如果是外部的用戶怎么辦秫舌,我沒法拿他的手機去測試。

其實這個問題很常見绣檬,但是這次我覺得這個問題如果不是我們自己同事發(fā)現(xiàn)的足陨,那就很恐怖,可能廢很大精力才能查出問題娇未,甚至會導致很嚴重的線上bug墨缘,細思極恐,剛好前不久成都FCC的大前端交流會上葉小釵談到了監(jiān)控這塊零抬,也讓我有所啟發(fā)镊讼,這些公共服務才是公司的核心財富,目前公司業(yè)務發(fā)展處在上升階段平夜,未來用戶肯定會越來越多蝶棋,對系統(tǒng)的穩(wěn)定性要求也會越來越高,那既然我們還缺乏這塊的服務忽妒,現(xiàn)在做正合適玩裙。

前期準備

從提出這個想法的一開始就知道兼贸,落地才是關鍵,否則一切空談献酗。? 剛好半個多月以后寝受,我們前端組需要在公司做一次分享,我現(xiàn)在做個題材就挺適合分享的罕偎,其他后端和測試同事也容易聽進去一點很澄。??最開始我考慮了后端存儲和可視化的情況,想找個現(xiàn)成后端集成工具幫我處理后端的工作颜及。? 就找后端同事問了一下甩苛,同事推薦了Elasticsearch+Fluentd+Kibana 。然后稍微研究了一下俏站,總覺得哪里不對讯蒲,反正研究了之后發(fā)現(xiàn)可能還是需要做一些定制開發(fā)才能解決需求,后端同事聽了我的需求也是這么說的肄扎。一人之力有限墨林,并且公司業(yè)務上的事情也多,找一個后端同事配合極好犯祠,利用各自的優(yōu)勢可以更快落地旭等,這樣我也可以專注前端的工作和把控整個項目落地。? 就這樣衡载,我和后端同事商量了一下搔耕,他也答應抽空和我一起搞了。? ?拋開后端的事情痰娱,我開始思考前端的工作弃榨,去調(diào)研一下別人的方案和這塊的知識。? 有一些三方庫或者開源項目提供類似的功能的梨睁,做了很簡單的了解鲸睛。? 最后想著自己開發(fā)更容易去適應自身的業(yè)務,并且目前第一版的需求功能也并沒有那么大的開發(fā)量坡贺,那就自己做吧腊凶。? 前期遇見了一些需要解決和實現(xiàn)的功能點: 生成sourcemap,監(jiān)聽js報錯和信息上報拴念,壓縮的js代碼上報后sourcemap解析問題,如何更平滑的應用在業(yè)務項目中褐缠,數(shù)據(jù)存儲優(yōu)化等政鼠。

基本實現(xiàn)

前端

????● js報錯事件監(jiān)聽+處理上報

????● 構建工具生成sourcemap文件

????● sourcemap文件上傳

后端

????● 提供接口收集報錯

????● 讀取sourcemap文件,解析上傳的報錯(解析發(fā)生時間:接口收集到后馬上處理队魏,后期提取的時候處理)

????● 存儲數(shù)據(jù)

監(jiān)聽js報錯和信息上報

通過onerror我們能監(jiān)聽和拿到js的報錯信息公般, 可以拿到如下代碼的五個參數(shù)万搔。? columnNo, error這兩個參數(shù)在一些老版本的IE8-9瀏覽器和opera低版本等瀏覽器上可能拿不到,但是沒有關系官帘,我們在代碼上兼容拿不到參數(shù)的情況瞬雹,如果缺少后兩個參數(shù),傳空值就行了刽虹。? 也可以通過其他方式拿到這些老版本瀏覽器的columnNo和error參數(shù)酗捌,目前監(jiān)控主要是針對移動端,也沒太大必要去兼容老版本的瀏覽器涌哲。


onerror方法大致實現(xiàn)如下:

可能存在跨域問題胖缤,不同域下的js需要配置script屬性crossorigin="anonymous"和后端配置Access-Control-Allow-Origin,但是目前我們的項目不存在js跨域問題阀圾。

現(xiàn)在我們能通過onerror拿到報錯信息了哪廓,可是線上的代碼是經(jīng)過壓縮的,報錯的時候我們能拿到的的行列數(shù)和變量命都不能告訴我們源代碼哪里出錯了初烘。這里我們需要用到sourcemap涡真,下面來講講它。

sourcemap

sourcemap就是一個信息文件肾筐,里面儲存著位置信息哆料。? 也就是說,sourcemap文件記錄了代碼轉換前的位置和轉換后對應的位置(http://www.ruanyifeng.com/blog/2013/01/javascript_source_map.html 阮一峰詳解)局齿。? 下面圖1是login.js的壓縮版本剧劝,第二行的注釋指定了map文件的相對路徑,瀏覽器根據(jù)注釋會找到map文件然后自動解析出來抓歼,在調(diào)試器里就可以看到源碼了讥此;? 圖2是map文件(json格式);? 圖3圖4介紹sourcemap文件谣妻。? 圖2我們生成的map文件sourcesContent字段直接引入了源文件代碼(構建工具可以配置是否給map文件引入源文件)萄喳,這樣可以方便后端解析,如果沒有源文件對應的話后端是解析不出正確結果的蹋半。

(圖1)

(圖2)

(圖3)

(圖4)

grunt生成sourcemap:

我們的移動端項目構建工具比較老了他巨,統(tǒng)一用的grunt作為打包工具。? 之前沒有在壓縮代碼時使用sourceMap减江,因為開發(fā)和測試環(huán)境沒有壓縮染突,所以也不需要在瀏覽器用sourceMap調(diào)試。? 然后我就再去修改gruntfile文件(之前不是我寫的)辈灼,sourceMap配置感覺和官方文檔對不上份企,老是報錯,最后才發(fā)現(xiàn)之前的打包工具的依賴版本是13年的了巡莹,也暫時沒必要去折騰版本問題了司志,把老版本的文檔翻出來再配置了一下sourcemap文件就成功的生成在源文件的同級目錄下了甜紫,比如源文件叫xx.js,map文件就是xx.js.map骂远。? 我們給js文件加上了md5版本號囚霸,所以實際的文件是xx.md5.js和xx.md5.js.map(md5是根據(jù)內(nèi)容變化的)。

sourcemap解析問題

思考的時候發(fā)現(xiàn)最大的難點應該在sourcemap解析激才。? 最開始后端同事以為sourcemap是nodejs生成的文件拓型,他們后端用的go或者php似乎不能解析吧,如果知道了sourcemap原理就應該知道贸营,它只是一種數(shù)據(jù)格式和開發(fā)語言沒關系吨述。? 我把map文件和報錯信息交給后端同事,他們用go語言的一個工具成功解析出了答案钞脂,實現(xiàn)了本地文件的解析揣云。? 但是我們需要的是自動化解析,不可能每次都去把存儲的報錯信息手動的拿出來再去找對應的map文件做人工解析冰啃。? 所以需要我們后端程序自己去找到map文件邓夕,并解析報錯信息。

如此一來阎毅,后端解析存在兩個關鍵問題:

? ? ● map文件存儲在哪里

????● 什么時候解析

①map文件存儲在哪里

這里只說我們的方案焚刚,map文件和源js文件打包到同級目錄下,一起上傳到服務器(比如js的路徑是www.xxx.com/dist/index.md5.js扇调,那map文件的地址就是www.xxx.com/dist/index.md5.js.map)矿咕,服務端就可以根據(jù)報錯的js路徑再加上.map后綴找到map文件。? 壓縮文件有一段注釋描述sourceMappongURL指定了map文件的位置狼钮,打開瀏覽器之后調(diào)試器會找到這個map文件碳柱,在瀏覽器里就能看到源代碼,為了避免這種情況熬芜,需要服務器配置.js.map后綴的文件不可訪問莲镣。? 如果這樣的話,服務器解析的時候不能直接去下載靜態(tài)資源.map文件涎拉,而是需要去找到服務器本地對應的map文件瑞侮,這樣要單獨配置路徑和寫邏輯很麻煩,而且文件夾結構有變動的話也不靈活鼓拧。? 所以我們的方案是做token權限校驗半火,map文件必須加正確的token參數(shù),服務器才會返回資源(xxx.js.map?token=xxxx)季俩,否則nginx會屏蔽沒有token或者token錯誤的請求慈缔。

②什么時候解析

兩種方法,一種是后端接口收到報錯信息之后种玛,馬上找到map文件藐鹤,并解析存儲到數(shù)據(jù)庫。? 一種是先保留上報信息赂韵,通過接口查詢的時候再去解析娱节。? 我們選擇了前者,接口收到數(shù)據(jù)之后祭示,后端根據(jù)當前報錯文件的url肄满,去查查本地是否已經(jīng)下載過當前文件,如果已經(jīng)存在這個文件质涛,就直接用本地的文件解析稠歉,如果本地沒有,路徑加上.map和token參數(shù)汇陆,下載對應的map文件到本地怒炸,然后再去讀取當前本地文件并解析,解析的數(shù)據(jù)和上報的數(shù)據(jù)就存為一條記錄毡代。? 如果是后者的方法阅羹,存在很多麻煩的問題,這里不多說了教寂。

一張圖詳細描述我們的解析流程:

有一種情況可能發(fā)生: 當前項目已經(jīng)更新到1.1版本了捏鱼,1.0版本的一個報錯以前沒被觸發(fā),這個時候有個用戶緩存了1.0版本的代碼酪耕,并且觸發(fā)了一個新的報錯导梆,這個時候服務器本地存儲的map文件里沒有這個文件,就會帶上token去下載map文件迂烁,因為當前已經(jīng)是1.1版本了看尼,原js文件發(fā)生過變動,md5的版本已經(jīng)對應不上了婚被,這個時候就沒法找到map文件了狡忙,無法解析,所以這種特殊情況只能存儲上報的errorInfo信息址芯。

如何更平滑的應用在業(yè)務項目中

目前js的onerror方法只有代碼量不大灾茁,后期還會有疊加。現(xiàn)在的想法是盡量不和業(yè)務代碼做過多接觸谷炸,只需要直接引入當前js到各個業(yè)務項目中去北专,每個項目不用對它太多任何配置,讓它盡量單純一點旬陡。

存儲優(yōu)化

后期是會做管理后臺來查詢和統(tǒng)計這些異常日志的拓颓,同一個錯誤可能上傳報錯數(shù)據(jù)到服務端,后端查詢出來是一條條獨立的記錄描孟,我們不能區(qū)分這條記錄的報錯是不是有重復數(shù)據(jù)驶睦,也不應該讓后端去做字段對比砰左。? 后來想到給報錯的文件路徑+行+列信息拼在一起字段做md5生成,根據(jù)這個唯一值生成md5场航,最后查詢的時候只需要查詢當前md5字段就能知道這一條報錯一個有多少條記錄缠导。? 不過我想的太天真了,不同的瀏覽器報錯行列信息有點不一樣溉痢,同一報錯就可能生成不同的md5字符串僻造,即便這里有點問題,我還是繼續(xù)用這個方案保存了md5(因為內(nèi)核原因孩饼,移動端的差異還是比較小髓削,當前字段也能有一定的區(qū)分性)。

我們第一版存儲的主要數(shù)據(jù)(還有一些常規(guī)的就不說) :


發(fā)送郵件

郵件提醒是很有必要的一個功能镀娶,目前已經(jīng)實現(xiàn)實時郵件提醒功能立膛。 公司企業(yè)郵箱建個單獨的郵箱就叫frontendmonitor@吧,當后端接口收到報錯后汽畴,把解析數(shù)據(jù)通過這個郵箱發(fā)送給前端旧巾,達到提醒效果。? ?如果是用QQ郵箱或者個人郵箱應該需要在賬戶里開啟smtp服務忍些,QQ企業(yè)郵箱是默認開啟此功能的鲁猩。? 郵件功能要注意性能和優(yōu)化問題,不能因為前端報錯太多導致服務器掛掉罢坝。

實際使用后的優(yōu)化

我們發(fā)現(xiàn)不同的瀏覽器報錯的變量可能不一樣廓握,同一個報錯在chrome瀏覽器和firefox上columnNo參數(shù)一點偏差。? 用兩種報錯解析了一下嘁酿,如下圖隙券,報錯的代碼都是18行,是沒問題的闹司,F(xiàn)irefox報錯是下圖第一個:console 18 0 true娱仔,chrome是testBase 18 0 true,行數(shù)沒問題游桩,偏差不影響我們最終查錯牲迫,我的18行源代碼是:console.log(testBase)。? testBase是故意沒有申明借卧,testBase是undefined盹憎,出問題的應該是testBase這個變量,過從報錯情況上看铐刘,確實是谷歌瀏覽器更精準一點陪每。? 雖然不在意IE,不過IE11報錯列數(shù)和firefox一致。

頁面觸發(fā)事件報錯檩禾,用戶一直觸發(fā)按鈕挂签,這時就會不停上報錯誤信息。解決:存儲上一個報錯信息和時間盼产,進行比對竹握,同一個報錯,短時間內(nèi)避免一直重復發(fā)送辆飘。

框架模板報錯,被框架本身捕獲谓传,不會觸發(fā)window.onerror蜈项,需要使用框架本身的全局監(jiān)聽捕獲信息后手動上傳,這里需要加手動上傳錯誤信息的方法续挟。

引入監(jiān)控的項目紧卒,由于業(yè)務原因可能需要上傳一些業(yè)務信息方便分析,所以預留一個配置字段诗祸,上傳錯誤的時候請求會帶上業(yè)務相關信息跑芳。

總結

這種非業(yè)務服務,來源于個人興趣和思考直颅,并沒有上層壓力需要你做或者什么時候做完博个。? 從最開始有個想法、去調(diào)研功偿、去找后端同事求助盆佣、 開干到最終落地。? 這個過程需要自己堅持做下去械荷,因為害怕自己不能最終落地共耍,所以抓緊時間,一步步去實現(xiàn)每個細節(jié)的想法吨瞎,讓事情盡快落地和上線痹兜,以免自己對這個事情越拖越久。? 作為需求方颤诀,更好的把握整個項目字旭,加上自己的興趣,所以這次自己也學習了一點go語言着绊,保證能看懂后端代碼和了解后端邏輯谐算,最好能做一點開發(fā),這次在后端同事代碼的基礎上归露,實現(xiàn)了發(fā)郵件的小功能洲脂,我稱之為淺入淺出,裝完逼就跑路~? 現(xiàn)在第一版已經(jīng)上線,并且在剛上線不到兩個小時恐锦,就收到了報錯郵件往果,嚇得我急忙查找bug,很快查出來了問題來一铅,這個bug應該存在很久了陕贮,但是因為沒有阻塞性,并且沒有影響到業(yè)務潘飘,也一直沒被發(fā)現(xiàn)肮之,結論是我們這個前端異常監(jiān)控功能還是很成功!? 后期還有很多功能需要開發(fā)卜录,統(tǒng)計戈擒、數(shù)據(jù)可視化、智能報警等等艰毒。? 第一版落地筐高,就為以后的迭代和進化打下了良好基礎。

在做這個事情的過程中丑瞧,我是想盡快把事情落地柑土,時間也很緊張,也并沒有做非常充分的調(diào)研绊汹,比如現(xiàn)成的一些開源項目是怎么做的稽屏。? 后來從同事那里了解到sentry這些三方開源項目之后,也有一點失落過灸促,雖然我也解決了我的需求诫欠,但是三方的開源項目是一個非常完善的系統(tǒng)术陶,提供了很多功能喘落,比我這個強大多了,那我做這個到底有什么意義广凸, 感覺完全和別人比拼不上典鸡,未來我這個項目會繼續(xù)迭代嗎被廓,有繼續(xù)迭代的必要嗎?? ?以后有特殊定制化的需求的時候萝玷,也許自己開發(fā)的才容易更適應業(yè)務嫁乘,可是有那個機會嗎?? 這一次落地已經(jīng)達到我最初的要求了球碉,也能幫我解決目前問題蜓斧,未來還有很多挑戰(zhàn)和迭代等待著,我會帶著它一路過關斬將睁冬,還是半路死掉挎春?? ?我想說:

最后大力地感謝我司后端同事的大力支持!!~

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末直奋,一起剝皮案震驚了整個濱河市能庆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脚线,老刑警劉巖搁胆,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異邮绿,居然都是意外死亡渠旁,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門船逮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來一死,“玉大人,你說我怎么就攤上這事傻唾。” “怎么了承耿?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵冠骄,是天一觀的道長。 經(jīng)常有香客問我加袋,道長凛辣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任职烧,我火速辦了婚禮扁誓,結果婚禮上,老公的妹妹穿的比我還像新娘蚀之。我一直安慰自己蝗敢,他們只是感情好,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布足删。 她就那樣靜靜地躺著寿谴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪失受。 梳的紋絲不亂的頭發(fā)上讶泰,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音拂到,去河邊找鬼痪署。 笑死,一個胖子當著我的面吹牛兄旬,可吹牛的內(nèi)容都是我干的狼犯。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼辜王!你這毒婦竟也來了劈狐?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤呐馆,失蹤者是張志新(化名)和其女友劉穎肥缔,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汹来,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡续膳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了收班。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坟岔。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖摔桦,靈堂內(nèi)的尸體忽然破棺而出社付,到底是詐尸還是另有隱情,我是刑警寧澤邻耕,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布鸥咖,位于F島的核電站,受9級特大地震影響兄世,放射性物質(zhì)發(fā)生泄漏啼辣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一御滩、第九天 我趴在偏房一處隱蔽的房頂上張望鸥拧。 院中可真熱鬧,春花似錦削解、人聲如沸富弦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舆声。三九已至,卻和暖如春柳爽,著一層夾襖步出監(jiān)牢的瞬間媳握,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工磷脯, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蛾找,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓赵誓,卻偏偏與公主長得像打毛,于是被迫代替她去往敵國和親柿赊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • GitChat技術雜談 前言 本文較長幻枉,為了節(jié)省你的閱讀時間碰声,在文前列寫作思路如下: 什么是 webpack,它要...
    蕭玄辭閱讀 12,681評論 7 110
  • 性能優(yōu)化方向分類 請求數(shù)量: 合并腳本和樣式表熬甫, CSS Sprites胰挑, 拆分初始化負載, 劃分主域(使用“查找...
    Www劉閱讀 1,761評論 3 8
  • Some of the teachers make it complicated. 形容詞和副詞能做什么成分, 分...
    FredricZhu閱讀 757評論 0 0
  • 洗澡的時候郑象,我想了很多要寫的話贡这,在瀏覽器里溜達了這么一小會,腦子里東西都沒了厂榛,現(xiàn)在讓我寫盖矫,思緒有些枯竭。 好吧击奶,其...
    鐘慕橙菇?jīng)?/span>閱讀 147評論 0 0
  • 今天是我贊美自己的第十六天炼彪,么么噠!2017.3.3 我的一切都完美正歼,我深深的祝福自己并原諒自己,我知道我是最棒的...
    奧古全然當下閱讀 219評論 0 0