<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          前端監(jiān)控

          共 20877字,需瀏覽 42分鐘

           ·

          2021-08-10 16:33

          什么時候需要監(jiān)控

          1.當你的應用頻繁報錯找不到原因的時候。2.需要分析用戶興趣愛好、購買習慣。3.需要優(yōu)化程序的時候,可以做監(jiān)控收集數(shù)據(jù),做針對性的優(yōu)化。4.需要保證服務可靠性穩(wěn)定性。

          如果你的應用符合以上任意一條,就可以對應用實行監(jiān)控了。監(jiān)控的作用有兩個:事前預警和事后分析。

          事前預警:提前設(shè)置一個閾值,當監(jiān)控的數(shù)據(jù)達到閾值時,通過短信或者郵件通知管理員。例如 API 請求數(shù)量突然間暴漲,就得進行報警,否則可能會造成服務器宕機。

          事后分析:通過監(jiān)控日志文件,分析故障原因和故障發(fā)生點。從而做出修改,防止這種情況再次發(fā)生。

          本章內(nèi)容分為前端監(jiān)控原理分析和如何對項目實行監(jiān)控兩個部分。第一部分有三個小節(jié):數(shù)據(jù)采集、數(shù)據(jù)上報、擴展;第二部分只有一個小節(jié):如何使用 sentry[1] 實現(xiàn)項目監(jiān)控。

          好了,下面讓我們開始進入正文吧。

          數(shù)據(jù)采集

          性能數(shù)據(jù)采集

          性能數(shù)據(jù)采集需要使用 window.performance[2] API。

          Performance 接口可以獲取到當前頁面中與性能相關(guān)的信息,它是 High Resolution Time API 的一部分,同時也融合了 Performance Timeline API、Navigation Timing API、 User Timing API 和 Resource Timing API。

          從 MDN 的文檔可以看出,window.performance.timing 包含了頁面加載各個階段的起始及結(jié)束時間。

          這些屬性需要結(jié)合下圖一起看,更好理解:

          為了方便大家理解 timing 各個屬性的意義,我在知乎找到一位網(wǎng)友對于 timing 寫的簡介,在此轉(zhuǎn)載一下。

          timing: {        // 同一個瀏覽器上一個頁面卸載(unload)結(jié)束時的時間戳。如果沒有上一個頁面,這個值會和fetchStart相同。    navigationStart: 1543806782096,    // 上一個頁面unload事件拋出時的時間戳。如果沒有上一個頁面,這個值會返回0。    unloadEventStart: 1543806782523,
          // 和 unloadEventStart 相對應,unload事件處理完成時的時間戳。如果沒有上一個頁面,這個值會返回0。 unloadEventEnd: 1543806782523,
          // 第一個HTTP重定向開始時的時間戳。如果沒有重定向,或者重定向中的一個不同源,這個值會返回0。 redirectStart: 0,
          // 最后一個HTTP重定向完成時(也就是說是HTTP響應的最后一個比特直接被收到的時間)的時間戳。 // 如果沒有重定向,或者重定向中的一個不同源,這個值會返回0. redirectEnd: 0,
          // 瀏覽器準備好使用HTTP請求來獲取(fetch)文檔的時間戳。這個時間點會在檢查任何應用緩存之前。 fetchStart: 1543806782096,
          // DNS 域名查詢開始的UNIX時間戳。 //如果使用了持續(xù)連接(persistent connection),或者這個信息存儲到了緩存或者本地資源上,這個值將和fetchStart一致。 domainLookupStart: 1543806782096,
          // DNS 域名查詢完成的時間. //如果使用了本地緩存(即無 DNS 查詢)或持久連接,則與 fetchStart 值相等 domainLookupEnd: 1543806782096,
          // HTTP(TCP) 域名查詢結(jié)束的時間戳。 //如果使用了持續(xù)連接(persistent connection),或者這個信息存儲到了緩存或者本地資源上,這個值將和 fetchStart一致。 connectStart: 1543806782099,
          // HTTP(TCP) 返回瀏覽器與服務器之間的連接建立時的時間戳。 // 如果建立的是持久連接,則返回值等同于fetchStart屬性的值。連接建立指的是所有握手和認證過程全部結(jié)束。 connectEnd: 1543806782227,
          // HTTPS 返回瀏覽器與服務器開始安全鏈接的握手時的時間戳。如果當前網(wǎng)頁不要求安全連接,則返回0。 secureConnectionStart: 1543806782162,
          // 返回瀏覽器向服務器發(fā)出HTTP請求時(或開始讀取本地緩存時)的時間戳。 requestStart: 1543806782241,
          // 返回瀏覽器從服務器收到(或從本地緩存讀?。┑谝粋€字節(jié)時的時間戳。 //如果傳輸層在開始請求之后失敗并且連接被重開,該屬性將會被數(shù)制成新的請求的相對應的發(fā)起時間。 responseStart: 1543806782516,
          // 返回瀏覽器從服務器收到(或從本地緩存讀取,或從本地資源讀?。┳詈笠粋€字節(jié)時 //(如果在此之前HTTP連接已經(jīng)關(guān)閉,則返回關(guān)閉時)的時間戳。 responseEnd: 1543806782537,
          // 當前網(wǎng)頁DOM結(jié)構(gòu)開始解析時(即Document.readyState屬性變?yōu)椤發(fā)oading”、相應的 readystatechange事件觸發(fā)時)的時間戳。 domLoading: 1543806782573,
          // 當前網(wǎng)頁DOM結(jié)構(gòu)結(jié)束解析、開始加載內(nèi)嵌資源時(即Document.readyState屬性變?yōu)椤癷nteractive”、相應的readystatechange事件觸發(fā)時)的時間戳。 domInteractive: 1543806783203,
          // 當解析器發(fā)送DOMContentLoaded 事件,即所有需要被執(zhí)行的腳本已經(jīng)被解析時的時間戳。 domContentLoadedEventStart: 1543806783203,
          // 當所有需要立即執(zhí)行的腳本已經(jīng)被執(zhí)行(不論執(zhí)行順序)時的時間戳。 domContentLoadedEventEnd: 1543806783216,
          // 當前文檔解析完成,即Document.readyState 變?yōu)?'complete'且相對應的readystatechange 被觸發(fā)時的時間戳 domComplete: 1543806783796,
          // load事件被發(fā)送時的時間戳。如果這個事件還未被發(fā)送,它的值將會是0。 loadEventStart: 1543806783796,
          // 當load事件結(jié)束,即加載事件完成時的時間戳。如果這個事件還未被發(fā)送,或者尚未完成,它的值將會是0. loadEventEnd: 1543806783802}

          通過以上數(shù)據(jù),我們可以得到幾個有用的時間:

          // 重定向耗時redirect: timing.redirectEnd - timing.redirectStart,// DOM 渲染耗時dom: timing.domComplete - timing.domLoading,// 頁面加載耗時load: timing.loadEventEnd - timing.navigationStart,// 頁面卸載耗時unload: timing.unloadEventEnd - timing.unloadEventStart,// 請求耗時request: timing.responseEnd - timing.requestStart,// 獲取性能信息時當前時間time: new Date().getTime(),

          還有一個比較重要的時間就是白屏時間,它指從輸入網(wǎng)址,到頁面開始顯示內(nèi)容的時間。

          將以下腳本放在 </head> 前面就能獲取白屏時間。

          <script>    whiteScreen = new Date() - performance.timing.navigationStart    // 通過 domLoading 和 navigationStart 也可以    whiteScreen = performance.timing.domLoading - performance.timing.navigationStart</script>

          通過這幾個時間,就可以得知頁面首屏加載性能如何了。

          另外,通過 window.performance.getEntriesByType('resource') 這個方法,我們還可以獲取相關(guān)資源(js、css、img...)的加載時間,它會返回頁面當前所加載的所有資源。

          它一般包括以下幾個類型:

          ?sciprt?link?img?css?fetch?other?xmlhttprequest

          我們只需用到以下幾個信息:

          // 資源的名稱name: item.name,// 資源加載耗時duration: item.duration.toFixed(2),// 資源大小size: item.transferSize,// 資源所用協(xié)議protocol: item.nextHopProtocol,

          現(xiàn)在,寫幾行代碼來收集這些數(shù)據(jù)。

          // 收集性能信息const getPerformance = () => {    if (!window.performance) return    const timing = window.performance.timing    const performance = {        // 重定向耗時        redirect: timing.redirectEnd - timing.redirectStart,        // 白屏時間        whiteScreen: whiteScreen,        // DOM 渲染耗時        dom: timing.domComplete - timing.domLoading,        // 頁面加載耗時        load: timing.loadEventEnd - timing.navigationStart,        // 頁面卸載耗時        unload: timing.unloadEventEnd - timing.unloadEventStart,        // 請求耗時        request: timing.responseEnd - timing.requestStart,        // 獲取性能信息時當前時間        time: new Date().getTime(),    }
          return performance}
          // 獲取資源信息const getResources = () => { if (!window.performance) return const data = window.performance.getEntriesByType('resource') const resource = { xmlhttprequest: [], css: [], other: [], script: [], img: [], link: [], fetch: [], // 獲取資源信息時當前時間 time: new Date().getTime(), }
          data.forEach(item => { const arry = resource[item.initiatorType] arry && arry.push({ // 資源的名稱 name: item.name, // 資源加載耗時 duration: item.duration.toFixed(2), // 資源大小 size: item.transferSize, // 資源所用協(xié)議 protocol: item.nextHopProtocol, }) })
          return resource}

          小結(jié)

          通過對性能及資源信息的解讀,我們可以判斷出頁面加載慢有以下幾個原因:

          1.資源過多、過大2.網(wǎng)速過慢3.DOM 元素過多

          除了用戶網(wǎng)速過慢,我們沒辦法之外,其他兩個原因都是有辦法解決的,關(guān)于如何做性能優(yōu)化我們將在下一章學習。

          PS:其實頁面加載慢還有其他原因,例如沒有使用按需加載、沒有使用 CDN 等等。不過在這里我們強調(diào)的是僅通過對性能和資源信息的解讀來得知原因。

          錯誤數(shù)據(jù)采集

          目前所能捕捉的錯誤有三種:

          1.資源加載錯誤,通過 addEventListener('error', callback, true) 在捕獲階段捕捉資源加載失敗錯誤。2.js 執(zhí)行錯誤,通過 window.onerror 捕捉 js 錯誤。3.promise 錯誤,通過 addEventListener('unhandledrejection', callback)捕捉 promise 錯誤,但是沒有發(fā)生錯誤的行數(shù),列數(shù)等信息,只能手動拋出相關(guān)錯誤信息。

          我們可以建一個錯誤數(shù)組變量 errors 在錯誤發(fā)生時,將錯誤的相關(guān)信息添加到數(shù)組,然后在某個階段統(tǒng)一上報,具體如何操作請看下面的代碼:

          // 捕獲資源加載失敗錯誤 js css img...addEventListener('error', e => {    const target = e.target    if (target != window) {        monitor.errors.push({            type: target.localName,            url: target.src || target.href,            msg: (target.src || target.href) + ' is load error',            // 錯誤發(fā)生的時間            time: new Date().getTime(),        })    }}, true)
          // 監(jiān)聽 js 錯誤window.onerror = function(msg, url, row, col, error) { monitor.errors.push({ type: 'javascript', row: row, col: col, msg: error && error.stack? error.stack : msg, url: url, // 錯誤發(fā)生的時間 time: new Date().getTime(), })}
          // 監(jiān)聽 promise 錯誤 缺點是獲取不到行數(shù)數(shù)據(jù)addEventListener('unhandledrejection', e => { monitor.errors.push({ type: 'promise', msg: (e.reason && e.reason.msg) || e.reason || '', // 錯誤發(fā)生的時間 time: new Date().getTime(), })})

          小結(jié)

          通過錯誤收集,可以了解到網(wǎng)站發(fā)生錯誤的類型及數(shù)量,從而做出相應的調(diào)整,以減少錯誤發(fā)生。

          數(shù)據(jù)上報

          性能數(shù)據(jù)上報

          性能數(shù)據(jù)可以在頁面加載完之后上報,盡量不要對頁面性能造成影響。

          window.onload = () => {    // 在瀏覽器空閑時間獲取性能及資源信息    // https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback    if (window.requestIdleCallback) {        window.requestIdleCallback(() => {            monitor.performance = getPerformance()            monitor.resources = getResources()        })    } else {        setTimeout(() => {            monitor.performance = getPerformance()            monitor.resources = getResources()        }, 0)    }}

          當然,你也可以設(shè)一個定時器,循環(huán)上報。不過每次上報最好做一下對比去重再上報,避免同樣的數(shù)據(jù)重復上報。

          錯誤數(shù)據(jù)上報

          我在 DEMO(在小節(jié)末尾) 里提供的代碼,是用一個 errors 數(shù)組收集所有的錯誤,再在某一階段統(tǒng)一上報(延時上報)。

          其實,也可以改成在錯誤發(fā)生時上報(即時上報)。這樣可以避免“收集完錯誤,但延時上報還沒觸發(fā),用戶卻已經(jīng)關(guān)掉網(wǎng)頁導致錯誤數(shù)據(jù)丟失”的問題。

          // 監(jiān)聽 js 錯誤window.onerror = function(msg, url, row, col, error) {    const data = {        type: 'javascript',        row: row,        col: col,        msg: error && error.stack? error.stack : msg,        url: url,        // 錯誤發(fā)生的時間        time: new Date().getTime(),    }
          // 即時上報 axios.post({ url: 'xxx', data, })}

          另外,還可以使用 navigator.sendBeacon()[3] 來進行上報。

          window.addEventListener('unload', logData, false);function logData() {    navigator.sendBeacon("/log", analyticsData);}

          它的技術(shù)特點是:

          使用 sendBeacon() 方法會使用戶代理(瀏覽器)在有機會時異步地向服務器發(fā)送數(shù)據(jù),同時不會延遲頁面的卸載或影響下一導航的載入性能。這就解決了提交分析數(shù)據(jù)時的所有的問題:數(shù)據(jù)可靠,傳輸異步并且不會影響下一頁面的加載。

          DEMO 代碼

          <!DOCTYPE html><html><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <meta http-equiv="X-UA-Compatible" content="ie=edge">    <script>        function monitorInit() {            const monitor = {                // 數(shù)據(jù)上傳地址                url: '',                // 性能信息                performance: {},                // 資源信息                resources: {},                // 錯誤信息                errors: [],                // 用戶信息                user: {                    // 屏幕寬度                    screen: screen.width,                    // 屏幕高度                    height: screen.height,                    // 瀏覽器平臺                    platform: navigator.platform,                    // 瀏覽器的用戶代理信息                    userAgent: navigator.userAgent,                    // 瀏覽器用戶界面的語言                    language: navigator.language,                },                // 手動添加錯誤                addError(error) {                    const obj = {}                    const { type, msg, url, row, col } = error                    if (type) obj.type = type                    if (msg) obj.msg = msg                    if (url) obj.url = url                    if (row) obj.row = row                    if (col) obj.col = col                    obj.time = new Date().getTime()                    monitor.errors.push(obj)                },                // 重置 monitor 對象                reset() {                    window.performance && window.performance.clearResourceTimings()                    monitor.performance = getPerformance()                    monitor.resources = getResources()                    monitor.errors = []                },                // 清空 error 信息                clearError() {                    monitor.errors = []                },                // 上傳監(jiān)控數(shù)據(jù)                upload() {                    // 自定義上傳                    // axios.post({                    //     url: monitor.url,                    //     data: {                    //         performance,                    //         resources,                    //         errors,                    //         user,                    //     }                    // })                },                // 設(shè)置數(shù)據(jù)上傳地址                setURL(url) {                    monitor.url = url                },            }
          // 獲取性能信息 const getPerformance = () => { if (!window.performance) return const timing = window.performance.timing const performance = { // 重定向耗時 redirect: timing.redirectEnd - timing.redirectStart, // 白屏時間 whiteScreen: whiteScreen, // DOM 渲染耗時 dom: timing.domComplete - timing.domLoading, // 頁面加載耗時 load: timing.loadEventEnd - timing.navigationStart, // 頁面卸載耗時 unload: timing.unloadEventEnd - timing.unloadEventStart, // 請求耗時 request: timing.responseEnd - timing.requestStart, // 獲取性能信息時當前時間 time: new Date().getTime(), }
          return performance }
          // 獲取資源信息 const getResources = () => { if (!window.performance) return const data = window.performance.getEntriesByType('resource') const resource = { xmlhttprequest: [], css: [], other: [], script: [], img: [], link: [], fetch: [], // 獲取資源信息時當前時間 time: new Date().getTime(), }
          data.forEach(item => { const arry = resource[item.initiatorType] arry && arry.push({ // 資源的名稱 name: item.name, // 資源加載耗時 duration: item.duration.toFixed(2), // 資源大小 size: item.transferSize, // 資源所用協(xié)議 protocol: item.nextHopProtocol, }) })
          return resource }
          window.onload = () => { // 在瀏覽器空閑時間獲取性能及資源信息 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback if (window.requestIdleCallback) { window.requestIdleCallback(() => { monitor.performance = getPerformance() monitor.resources = getResources() console.log('頁面性能信息') console.log(monitor.performance) console.log('頁面資源信息') console.log(monitor.resources) }) } else { setTimeout(() => { monitor.performance = getPerformance() monitor.resources = getResources() console.log('頁面性能信息') console.log(monitor.performance) console.log('頁面資源信息') console.log(monitor.resources) }, 0) } }
          // 捕獲資源加載失敗錯誤 js css img... addEventListener('error', e => { const target = e.target if (target != window) { monitor.errors.push({ type: target.localName, url: target.src || target.href, msg: (target.src || target.href) + ' is load error', // 錯誤發(fā)生的時間 time: new Date().getTime(), })
          console.log('所有的錯誤信息') console.log(monitor.errors) } }, true)
          // 監(jiān)聽 js 錯誤 window.onerror = function(msg, url, row, col, error) { monitor.errors.push({ type: 'javascript', // 錯誤類型 row: row, // 發(fā)生錯誤時的代碼行數(shù) col: col, // 發(fā)生錯誤時的代碼列數(shù) msg: error && error.stack? error.stack : msg, // 錯誤信息 url: url, // 錯誤文件 time: new Date().getTime(), // 錯誤發(fā)生的時間 })
          console.log('所有的錯誤信息') console.log(monitor.errors) }
          // 監(jiān)聽 promise 錯誤 缺點是獲取不到行數(shù)數(shù)據(jù) addEventListener('unhandledrejection', e => { monitor.errors.push({ type: 'promise', msg: (e.reason && e.reason.msg) || e.reason || '', // 錯誤發(fā)生的時間 time: new Date().getTime(), })
          console.log('所有的錯誤信息') console.log(monitor.errors) })
          return monitor }
          const monitor = monitorInit()</script> <link rel="stylesheet" href="test.css"> <title>Document</title></head><body> <button class="btn1">錯誤測試按鈕1</button> <button class="btn2">錯誤測試按鈕2</button> <button class="btn3">錯誤測試按鈕3</button> <img src="https://avatars3.githubusercontent.com/u/22117876?s=460&v=4" alt=""> <img src="test.png" alt=""><script src="192.168.10.15/test.js"></script><script>document.querySelector('.btn1').onclick = () => { setTimeout(() => { console.log(button) }, 0)}
          document.querySelector('.btn2').onclick = () => { new Promise((resolve, reject) => { reject({ msg: 'test.js promise is error' }) })}
          document.querySelector('.btn3').onclick = () => { throw ('這是一個手動扔出的錯誤')}</script></body></html>

          擴展

          SPA

          window.performance API 是有缺點的,在 SPA 切換路由時,window.performance.timing 的數(shù)據(jù)不會更新。所以我們需要另想辦法來統(tǒng)計切換路由到加載完成的時間。拿 Vue 舉例,一個可行的辦法就是切換路由時,在路由的全局前置守衛(wèi) beforeEach 里獲取開始時間,在組件的 mounted 鉤子里執(zhí)行 vm.$nextTick 函數(shù)來獲取組件的渲染完畢時間。

          router.beforeEach((to, from, next) => {    store.commit('setPageLoadedStartTime', new Date())})
          mounted() {    this.$nextTick(() => {        this.$store.commit('setPageLoadedTime', new Date() - this.$store.state.pageLoadedStartTime)    })}

          除了性能和錯誤監(jiān)控,其實我們還可以收集更多的信息。

          用戶信息收集

          navigator

          使用 window.navigator[4] 可以收集到用戶的設(shè)備信息,操作系統(tǒng),瀏覽器信息...

          UV(Unique visitor)

          是指通過互聯(lián)網(wǎng)瀏覽這個網(wǎng)頁的訪客,00:00-24:00 內(nèi)相同的設(shè)備訪問只被計算一次。一天內(nèi)同個訪客多次訪問僅計算一個 UV。

          在用戶訪問網(wǎng)站時,可以生成一個隨機字符串+時間日期,保存在本地。在網(wǎng)頁發(fā)生請求時(如果超過當天24小時,則重新生成),把這些參數(shù)傳到后端,后端利用這些信息生成 UV 統(tǒng)計報告。

          PV(Page View)

          即頁面瀏覽量或點擊量,用戶每 1 次對網(wǎng)站中的每個網(wǎng)頁訪問均被記錄 1 個PV。用戶對同一頁面的多次訪問,訪問量累計,用以衡量網(wǎng)站用戶訪問的網(wǎng)頁數(shù)量。

          頁面停留時間

          傳統(tǒng)網(wǎng)站

          用戶在進入 A 頁面時,通過后臺請求把用戶進入頁面的時間捎上。過了 10 分鐘,用戶進入 B 頁面,這時后臺可以通過接口捎帶的參數(shù)可以判斷出用戶在 A 頁面停留了 10 分鐘。

          SPA

          可以利用 router 來獲取用戶停留時間,拿 Vue 舉例,通過 router.beforeEach、destroyed 這兩個鉤子函數(shù)來獲取用戶停留該路由組件的時間。

          瀏覽深度

          通過 document.documentElement.scrollTop 屬性以及屏幕高度,可以判斷用戶是否瀏覽完網(wǎng)站內(nèi)容。

          頁面跳轉(zhuǎn)來源

          通過 document.referrer 屬性,可以知道用戶是從哪個網(wǎng)站跳轉(zhuǎn)而來。

          小結(jié)

          通過分析用戶數(shù)據(jù),我們可以了解到用戶的瀏覽習慣、愛好等等信息,想想真是恐怖,毫無隱私可言。

          前端監(jiān)控部署

          前面說的都是監(jiān)控原理,但要實現(xiàn)還是得自己動手寫代碼。為了避免麻煩,我們可以用現(xiàn)有的工具 sentry[5] 去做這件事。

          sentry 是一個用 python 寫的性能和錯誤監(jiān)控工具,你可以使用 sentry 提供的服務(免費功能少),也可以自己部署服務?,F(xiàn)在來看一下如何使用 sentry 提供的服務實現(xiàn)監(jiān)控。

          注冊賬號

          打開 https://sentry.io/signup/ 網(wǎng)站,進行注冊。

          選擇項目,這里用 Vue 做示例。

          安裝 sentry 依賴

          選完項目,下面會有具體的 sentry 依賴安裝指南。

          根據(jù)提示,在你的 Vue 項目執(zhí)行這段代碼 npm install --save @sentry/browser @sentry/integrations @sentry/tracing,安裝 sentry 所需的依賴。

          再將下面的代碼拷到你的 main.js,放在 new Vue() 之前。

          import * as Sentry from "@sentry/browser";import { Vue as VueIntegration } from "@sentry/integrations";import { Integrations } from "@sentry/tracing";
          Sentry.init({ dsn: "xxxxx", // 這里是你的 dsn 地址,注冊完就有 integrations: [ new VueIntegration({ Vue, tracing: true, }), new Integrations.BrowserTracing(), ],
          // We recommend adjusting this value in production, or using tracesSampler // for finer control tracesSampleRate: 1.0,});

          然后點擊第一步中的 skip this onboarding,進入控制臺頁面。

          如果忘了自己的 DSN,請點擊左邊的菜單欄選擇 Settings -> Projects -> 點擊自己的項目 -> Client Keys(DSN)

          創(chuàng)建第一個錯誤

          在你的 Vue 項目執(zhí)行一個打印語句 console.log(b)。

          這時點開 sentry 主頁的 issues 一項,可以發(fā)現(xiàn)有一個報錯信息 b is not defined

          這個報錯信息包含了錯誤的具體信息,還有你的 IP、瀏覽器信息等等。

          但奇怪的是,我們的瀏覽器控制臺并沒有輸出報錯信息。

          這是因為被 sentry 屏蔽了,所以我們需要加上一個選項 logErrors: true。

          然后再查看頁面,發(fā)現(xiàn)控制臺也有報錯信息了:

          上傳 sourcemap

          一般打包后的代碼都是經(jīng)過壓縮的,如果沒有 sourcemap,即使有報錯信息,你也很難根據(jù)提示找到對應的源碼在哪。

          下面來看一下如何上傳 sourcemap。

          首先創(chuàng)建 auth token。

          這個生成的 token 一會要用到。

          安裝 sentry-cli 和 @sentry/webpack-plugin

          npm install sentry-cli-binary -gnpm install --save-dev @sentry/webpack-plugin

          安裝完上面兩個插件后,在項目根目錄創(chuàng)建一個 .sentryclirc 文件(不要忘了在 .gitignore 把這個文件添加上,以免暴露 token),內(nèi)容如下:

          [auth]token=xxx[defaults]url=https://sentry.io/org=woai3cproject=woai3c

          把 xxx 替換成剛才生成的 token。

          org 是你的組織名稱。

          project 是你的項目名稱,根據(jù)下面的提示可以找到。

          在項目下新建 vue.config.js 文件,把下面的內(nèi)容填進去:

          const SentryWebpackPlugin = require('@sentry/webpack-plugin')
          const config = { configureWebpack: { plugins: [ new SentryWebpackPlugin({ include: './dist', // 打包后的目錄 ignore: ['node_modules', 'vue.config.js', 'babel.config.js'], }), ], },}
          // 只在生產(chǎn)環(huán)境下上傳 sourcemapmodule.exports = process.env.NODE_ENV == 'production'? config : {}

          填完以后,執(zhí)行 npm run build,就可以看到 sourcemap 的上傳結(jié)果了。

          我們再來看一下沒上傳 sourcemap 和上傳之后的報錯信息對比。

          未上傳 sourcemap

          已上傳 sourcemap

          可以看到,上傳 sourcemap 后的報錯信息更加準確。

          切換中文環(huán)境和時區(qū)

          選完刷新即可。

          性能監(jiān)控

          打開 performance 選項,就能看到你每個項目的運行情況。具體的參數(shù)解釋請看文檔 Performance Monitoring[6]

          小結(jié)

          隨著 web 技術(shù)的發(fā)展,現(xiàn)在前端項目的規(guī)模也越來越大。在監(jiān)控系統(tǒng)的幫助下,我們可以更加清楚的了解項目的運行情況,根據(jù)采集到的錯誤數(shù)據(jù)和性能數(shù)據(jù)對項目做針對性的優(yōu)化。

          下一章我們將講解如何做性能優(yōu)化。

          參考資料

          ?7 天打造前端性能監(jiān)控系統(tǒng)[7]?zanePerfor[8]?sentry[9]

          References

          [1] sentry: https://docs.sentry.io/
          [2] window.performance: https://developer.mozilla.org/zh-CN/docs/Web/API/Performance
          [3] navigator.sendBeacon(): https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator/sendBeacon
          [4] window.navigator: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/navigator
          [5] sentry: https://docs.sentry.io/
          [6] Performance Monitoring: https://docs.sentry.io/product/performance/
          [7] 7 天打造前端性能監(jiān)控系統(tǒng): https://fex.baidu.com/blog/2014/05/build-performance-monitor-in-7-days/
          [8] zanePerfor: https://github.com/wangweianger/zanePerfor
          [9] sentry: https://docs.sentry.io/


          瀏覽 47
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  69视频免费观看 | 鸡巴在线观看 | 亚洲爽爽 | 在线免费看黄色视频 | 国产三级视频 |