Sentry-JavaScript
Sentry是一套用於捕獲產品錯誤的開源專案,其下支援很多語言、框架。
這裡就只闡述在前端JavaScript方向的處理操作
在我們公司之前的應用場景裡,很多專案都是使用kibana
來做資訊統計。但是我們無法清楚的知道應用的執行狀態是怎麼樣的。當某個客戶在使用我們開發產品時,如果報錯、崩潰。使用者只能向客服尋求幫助,再交接給我們的開發人員進行復現、修復。其中因為不清楚具體的資料,開發人員是在復現時會非常的耗時。
而Sentry
的用途就是解決這一痛點問題,讓開發人員快速準確的定位到問題的根源所在,以達到快速修復,讓開發人員更注重於開發新的功能上面。減少時間資源上的浪費。
1. JavaScript
1.1. 接入
因為Sentry
使用的是一種Hook
錯誤函式的技術,來達到捕獲錯誤的目的,所以我們基本可以無損耗的接入到現有的專案中去。
下面是React
與Sentry
進行結合的一些基本步驟。
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 | 不能 |
可以發現其瀏覽器都支援此方法。只是有些執行環境不支援colNo
和errorObj
,但是這塊,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. 展示資訊
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崩潰的時候,看到起崩潰的上下文了。如下圖:
這樣就可以準確的定位到是哪裡出現了問題。
3. 淺入上傳檢索的原理
當Sentry服務端收到source-map
時,是通過你上傳時的url-prefix
資訊,與source-map檔案以及執行時的js檔案,產生對應。流程圖如下: