Vue SPA專案 + Sentry 實現前端錯誤監控

FrankCheung發表於2019-03-03

這篇文章也發在我的部落格,歡迎圍觀?

前端錯誤監控的必要性

前端監控是相對於後端監控而言的,以往的後端監控只能記錄介面被請求之後所發生的錯誤,但是現在隨著使用者複雜度不斷提高,很多錯誤是在後端介面被請求以前就發生的JS錯誤。對於這種錯誤,傳統的後端錯誤監控是無能為力的,因此前端監控應運而生。

為什麼選擇Sentry

最近想在公司的專案上部署前端監控,以主動捕捉使用者端的錯誤(滿足我們自己的控制慾?),不再等待使用者的反饋(事實上使用者的反饋少之又少?)。本來考慮自己寫一個,奈何水平有限,加之看到已經有不少成熟的方案,所以...你們懂得!目前較為成熟的前端監控方案,具體參考知乎帖子 如何做前端異常監控 ,大致上可供選擇的方案如下:

  1. Sentry
  2. Fundebug
  3. Bugsnag
  4. BetterJS

因為是想部署到公司自己的伺服器上,上述貌似只有Sentry和BetterJS有提供自行部署的方案。然後考慮到目前前端專案都是壓縮打包後再發布的,能夠結合sourcemaps對錯誤進行定位是非常有必要的,因此從兩者中選擇了Sentry。(上述方案中,Fundebug也是支援sourcemaps的)

如何使用

作為試用,我選擇使用Sentry提供的服務,註冊賬號之後,選擇使用免費版的服務,就可以開始在前端對我們的專案加入前端錯誤監控了。

初步引入錯誤監控模組

首先,當然是要看Sentry提供的docs了,建立專案的步驟可以說是介紹得非常清楚了。

  1. Create a new project
  2. Choose a language or framework
  3. Then follow the docs

OK,建立一個新專案之後,就應該到我的前端專案中引入監控的模組了。此處,因為我的專案是使用Vue的SPA專案,所以使用的是Sentry官方推薦的Raven.js。下載該模組之後,按照官方指引在專案中引入檔案,其中key和project在你註冊賬號之後官方都會自動幫你生成的,非常貼心。

// main.js

import Raven from 'raven-js'
import RavenVue from 'raven-js/plugins/vue'

Raven
  .config('https://<key>@sentry.io/<project>')
  .addPlugin(RavenVue, Vue)
  .install()
  
複製程式碼

這時候,你只要在你專案中的一個不起眼的角落埋下一個錯誤,然後去觸發一下,就能看到呼叫了raven.js傳送錯誤,並且在你的sentry專案中也能看到相關報錯了。

sentry報錯記錄

但是這樣的報錯資訊其實意義不大,除了能夠看到具體的error原因外,錯誤位置根本無從定位。如果錯誤資訊沒有具體到我們足以馬上定位出錯誤位置,那麼我們只能一遍遍地對程式碼進行排查,耗時耗力。這時候就要使用sourcemaps對錯誤進行定位了,所幸Sentry對此的支援也是非常好的。

引入sourcemaps對錯誤進行定位

首先,我們來看官方文件對引入sourcemaps的說明。Sentry允許我們通過三種方式使用sourcemaps,releases API, sentry-cli, sentry-webpack-plugin。考慮到專案構建過程中就一併提交sourcemaps,我個人僅僅實踐了最後一種。


// 來自官方的步驟

1. Start by creating a new authentication token under **[Account] > API**.
2. Ensure you have project:write selected under scopes.
3. Install @sentry/webpack-plugin using npm
4. Create .sentryclirc file with necessary config (see Sentry Webpack Plugin docs below)
5. Update your webpack.config.json

複製程式碼

下面我們來實踐一下:

前兩步,非常簡單,略過略過。

對於第三步, 我個人發現僅僅install @sentry/webpack-plugin似乎還是不夠的,還需要install @sentry/cli,不知道是我個人問題,敬請指出。

第四步,可能是我對這種配置格式不太熟悉,折騰最久就是這一步了。給出官方配置說明,下面是我的基礎配置(其實就是將如defaults.url,auth.token等拆分,寫入配置檔案即可),在專案根目錄下:

// .sentryclirc

[defaults]
url = https://sentry.io/
<!-- 此處可以從你的sentry.io的全路徑看出,如:https://sentry.io/此處是你的org/此處是你的project/ -->
org = 
project = 

[auth]
token = 此處就是你第一步第二步建立的token


複製程式碼

第五步,更新我的webpack配置,配置我的監控模組

此處參考了一位兄弟的文章,他用了另外一個Plugin實現,請圍觀。

此處宣告,這位大兄弟文中的方法都很好,但是對於需要擷取7位數的引數作為版本號的問題,我個人實踐是擷取後Raven.js無法傳遞正確版本號了,反而不擷取能夠傳遞正確版本號!通過檢視Raven.js的post,發現release非常長,不止7位。

下面這個步驟的urlPrefix屬性特別關鍵,這個是給上傳的檔案新增字首的,因為sentry除了根據版本號,還要匹配特定版本號中的路徑。這個屬性的預設值是~/,而~是僅僅是去掉了網址前面的協議和域名,即拼接起來的map資源路徑是http://host/static/js/app.js.map。但是如果像我的站點,多了一級路徑,那麼就需要配置這個屬性了,否則上傳到Sentry的maps就無法訪問到了。

// webpack.prod.conf.js

const SentryPlugin = require('@sentry/webpack-plugin');

plugins: [
    new SentryPlugin({
      include: './dist',
      release: process.env.RELEASE_VERSION,
      configFile: 'sentry.properties',
      urlPrefix: '~/TechPage/', // 如果不需要也可以不傳這個參
    }),
]

複製程式碼

就是下面這個步驟,不應該擷取

// prod.env.js

let gitSha = require('child_process').execSync('git rev-parse HEAD').toString().trim()

// process.env.RELEASE_VERSION = gitSha.substr(2, 9) 不應擷取

process.env.RELEASE_VERSION = gitSha

module.exports = {
  RELEASE_VERSION: `"${gitSha}"`,
  NODE_ENV: '"production"'
}

複製程式碼
// main.js
import Raven from 'raven-js'
import RavenVue from 'raven-js/plugins/vue'

Raven
  .config('https://<key>@sentry.io/<project>', {
    release: process.env.RELEASE_VERSION,
    debug: true
  })
  .addPlugin(RavenVue, Vue)
  .install()

複製程式碼

由於sentry是通過release版本匹配一致的方式,使用特定版本的sourcemaps去定位錯誤的,因此我們需要在專案構建的時候生成一個特定的版本號,將這個版本號賦值給Raven.js以及SentryPlugin,這樣就能形成對應關係。當然你也可以通過另外的方式生成相應的release版本號,這都是可以的,只要是能夠唯一對應就可以了。即使你沒有形成對應關係,但只要你釋出了source maps,Sentry預設是會根據js檔案中的sourceMappingURL去找到map檔案,然後定位錯誤的。

Raven.js的配置官方文件也是有詳細說明的,詳情點選。此處我僅僅配置了release以及debug,設定debug為true的話,Raven.js會將一些debug資訊輸出到控制檯。

至此,你觸發專案中的錯誤,就能獲得下面的效果,錯誤資訊也成功定位了,非常的清楚。

控制檯資訊
Sentry資訊

使用webpack-sentry-plugin上傳sourcemaps,並且在上傳後刪除,不讓終端使用者接觸maps檔案

此處是參照上面提到那位兄弟的做法了,不過他提到了要在上傳sourcemaps到sentry之後刪除,不讓終端使用者接觸,這是對的 。但是我這邊刪除之後,使用者端發生錯誤之後,沒有辦法把定位後的錯誤資訊返回了,返回的錯誤資訊都是編譯打包之後的程式碼的,可讀性一般。如果發現我哪裡配置錯誤,敬請指出。

經過踩坑,正是由於沒有正確配置urlPrefix(@sentry/webpack-plugin中的屬性,webpack-sentry-plugin中是配置filenameTransform方法),所以當我不釋出source maps時,無法定位錯誤。



const SentryPlugin = require('webpack-sentry-plugin');

plugins: [
    new SentryPlugin(Object.assign({
      release: process.env.RELEASE_VERSION,
      deleteAfterCompile: true,
      suppressErrors: true,
      /** filenameTransform: function (filename) {
        var pub = config.build.assetsPublicPath
        if (/^\/\//.test(pub)) pub = 'http:' + pub
        var urlObj = require('url').parse(pub)
        return '~' + urlObj.pathname.replace(/\/+$/, '') + '/' + filename
      } */
      filenameTransform: function (filename) {
         return '~/TechPage/' + filename
      },
    }, require('../sentry.conf.js'))),
]

複製程式碼
// sentry.conf.js(位於根目錄)

module.exports = {

// 此處可以從你的sentry.io的全路徑看出,如:https://sentry.io/此處是你的org/此處是你的project
  organisation: '', 
  project: '',
  apiKey: ''
}

複製程式碼

這種配置,我得到的報錯資訊是這樣的,如下圖:

經過配置,能夠在不釋出source maps的情況下,得到完整的錯誤定位!

詳盡報錯

最後的最後

如果想將Sentry部署到自己的伺服器,Sentry官方也有詳細的文件,各位請移步。

各位看官如果發現文中我的錯處,請一定不要嫌麻煩,請開展花式吐槽!謝謝!

也歡迎上我的Demo網站點選建立時間一欄觸發錯誤看看Sentry的效果,謝謝!

Vue SPA專案 + Sentry 實現前端錯誤監控

此處感謝 @時間是海 的提醒,參考了sentry社群裡的問題才注意到urlPrefix這個問題。附上社群的兩篇帖子:

  1. JS source maps issue
  2. Doesn’t find uploaded source map file (with tilde ~)

相關文章