JavaScript整合Sentry

BlackHole1發表於2018-08-24

Sentry-JavaScript

Sentry是一套用於捕獲產品錯誤的開源專案,其下支援很多語言、框架。

這裡就只闡述在前端JavaScript方向的處理操作

在我們公司之前的應用場景裡,很多專案都是使用kibana來做資訊統計。但是我們無法清楚的知道應用的執行狀態是怎麼樣的。當某個客戶在使用我們開發產品時,如果報錯、崩潰。使用者只能向客服尋求幫助,再交接給我們的開發人員進行復現、修復。其中因為不清楚具體的資料,開發人員是在復現時會非常的耗時。

Sentry的用途就是解決這一痛點問題,讓開發人員快速準確的定位到問題的根源所在,以達到快速修復,讓開發人員更注重於開發新的功能上面。減少時間資源上的浪費。

1. JavaScript

1.1. 接入

因為Sentry使用的是一種Hook錯誤函式的技術,來達到捕獲錯誤的目的,所以我們基本可以無損耗的接入到現有的專案中去。

下面是ReactSentry進行結合的一些基本步驟。

React:

#SentryBoundary.js
import { Component } from "react";
import Raven from "raven-js";

export default class SentryBoundary extends Component {
  constructor(props) {
    super(props);
    this.state = { error: null };
  }

  componentDidCatch(error, errorInfo) {
    this.setState({ error });
    // 傳送錯誤資訊
    Raven.captureException(error, { extra: errorInfo });
  }

  render() {
    if (this.state.error) {
      // 此處可以寫成元件,當元件崩潰後,可以替換崩潰的元件
      console.log("React Error");
    }
    return this.props.children;
  }
}
複製程式碼
#index.js
Raven.config("DSN", {
  release: release,
}).install();

ReactDOM.render(
  <div>
    <SentryBoundary>
      <App />
    </SentryBoundary>
  </div>,
  document.getElementById("root")
);
複製程式碼

1.1.1. 上傳source-map

如果上面的程式碼已經配置好後,那麼現在的應用是可以捕獲到錯誤的,但是存在了一個問題,我們目前的專案大多都使用webpack進行打包,而打包後的程式碼是混淆加密的程式碼,無法讓我們準確的知道丟擲錯誤的位置在哪裡。所以我們需要上傳source-map和混淆後的檔案一起上傳到Sentry伺服器上。方便我們快速查詢到問題所在的位置。

這個上傳的配置及命令是比較繁瑣的。也是專案結合Sentry的一個難點。

上傳source-map目前有兩種方式:

  • 使用Sentry提供的Webpack外掛進行配置,但是其靈活性不高。
  • 使用sentry-cli的,其靈活性比較高,可以針對不同專案進行單獨的配置。

其配置較為繁瑣,這裡就不在闡述。具體的React與Sentry結合的例子。可見我在github上的專案: react-sentry-demo。對每個配置都有詳細的說明。其中的上傳source-map,我使用的是第二種方法,並寫了一個指令碼,實現了: 打包、環境檢測、認證檢測、上傳source-map、刪除本地source-map的操作,完成自動化,可以把指令碼直接遷移到現有的專案中去,改動也不會太大。

其核心上傳命令如下:

sentry-cli releases files v1.8 upload-sourcemaps {js檔案和js.map所在目錄。如果沒有找到,sentry會遍歷其子目錄} --url-prefix '~/{過濾規則}'`;
複製程式碼

1.2. 淺入原理

在JavaScript中是有window.onerror這個方法的,而Sentry在前端的核心捕獲原理,就是通過重寫此方法,來對所有的錯誤進行捕獲。其實現的程式碼大致如下:

let _winError = window.onerror;
window.onerror = function (message, url, lineNo, colNo, errorObj) {
    console.log(`
	錯誤資訊: ${message}
	錯誤檔案地址: ${url}
	錯誤行號: ${lineNo}
	錯誤列號: ${colNo}
	錯誤的詳細資訊 ${errorObj}`);
}
複製程式碼

然後Sentry的工作就是獲取非錯誤的資料,如: user-agent瀏覽器資訊系統資訊自定義資訊等資訊,然後交給Sentry的生命週期函式,最後在把資料傳送到Sentry服務端,進行錯誤資訊展示。

1.2.1. 相容性

這裡所說的相容性,其實也就是window.onerror的相容性

1.2.1.1. 執行環境相容性

環境 message url lineNo colNo errorObj
Firefox
Chrom
Edge
IE 11
IE 10
IE 9
IE 8
Safari 10 and up
Safari 9
Opera 15+
Android Browser 4.4
Android Browser 4 - 4.3
微信webview(安卓)
微信webview(IOS)
WKWebview
UIWebview

1.2.1.2. 標籤相容性

標籤 window.onerror是否能捕獲
img 可以
script 需要再script標籤新增crossorigin屬性,並在服務端允許跨域。如果不使用這個屬性,錯誤資訊只會顯示Script error.
css 不能
iframe 不能

可以發現其瀏覽器都支援此方法。只是有些執行環境不支援colNoerrorObj,但是這塊,Sentry已經幫你處理好了,所以不用擔心。只是會在展示錯誤的時候,資訊不太完整而已。

1.3. 所能捕獲的資訊

1.3.1. 錯誤資訊

從上面的淺入原理可以看到,其核心捕獲是window.onerror。那麼只要它可以捕獲到的錯誤,都會傳送到Sentry上。

window.onerror能捕獲到的錯誤,除了Promise,基本上能在控制檯出現的錯誤,都會捕獲到。也就是執行時的錯誤,包括語法錯誤。

關於捕獲Promise錯誤的方案,可以使用:

window.addEventListener('unhandledrejection', event => {})

來進行捕獲,但是此事件的相容性不太好,目前只有webkit核心支援這個事件。

如下程式碼,是此方法所能捕獲到的:

const p = new Promise((reslove, reject) => reject('Error'))
p.then(data => {
  console.log(data)
})
// Promise觸發了reject回撥函式,但是卻沒有相應到catch來應對。從而導致報錯。
複製程式碼

1.3.2. 麵包屑資訊

  • Ajax請求
  • URL地址的變化
  • UI點選和按下的DOM事件
  • 控制檯的console資訊
  • 之前的錯誤
  • 自定義的麵包屑資訊

1.4. 展示資訊

image

2. Electron整合

這裡的整合,也不是說捕獲Electron應用的錯誤,而是崩潰。因為Electron只是一個容器,裡面的內容還是JavaScript應用。

2.1 接入

剛剛也說到這裡的整合也只是去捕獲Electron崩潰的資訊。而當Electron崩潰時,會觸發Electron的函式:crashReporter.start,那麼我們在這個函式裡去配置一下自己的sentry資訊:

import { crashReporter } from 'electron'

crashReporter.start({
  productName: 'aoc-desktop',
  companyName: 'alo7',
  submitURL:
    'https://sentry.com/api/34615/minidump/?sentry_key=3e05fe101f1f85008e853ff56908b7eb',  // sentry提供的minidump介面
  extra: {
    // 額外資訊
  }
})
複製程式碼

配置好後,可以使用process.crash()來模擬崩潰,以便檢視Sentry是否能收到崩潰資訊。

2.1.1 上傳Symbol(符號表)

在上面的應用說的是上傳source-map,但是這裡上傳的是Symbol。可以把Symbol理解為另一種source-map

Symbol的格式(字尾)有很多,Mac下是dSYM,windows是pdb。而在Sentry裡,暫時是不支援上傳pdb的。需要使用dump_syms.exe來把pdb格式轉化成sym格式。再上傳到Sentry裡。這樣就可以在Sentry崩潰的時候,看到起崩潰的上下文了。如下圖:

JavaScript整合Sentry

這樣就可以準確的定位到是哪裡出現了問題。

3. 淺入上傳檢索的原理

當Sentry服務端收到source-map時,是通過你上傳時的url-prefix資訊,與source-map檔案以及執行時的js檔案,產生對應。流程圖如下:

JavaScript整合Sentry

相關文章