1.簡介
Sentry 是一個開源的實時錯誤追蹤系統,可以幫助開發者實時監控并修復異常問題。它主要專注于持續集成、提高效率并且提升用戶體驗。Sentry 分為服務端和客戶端 SDK,前者可以直接使用它家提供的在線服務,也可以本地自行搭建;后者提供了對多種主流語言和框架的支持,包括 React、Angular、Node、Django、RoR、PHP、Laravel、Android、.NET、JAVA 等。同時它可提供了和其他流行服務集成的方案,例如 GitHub、GitLab、bitbuck、heroku、slack、Trello 等。目前公司的項目也都在逐步應用上 Sentry 進行錯誤日志管理。
2.本地搭建sentry服務
Sentry 本身是基于 Django 開發的,而且也依賴到其他的如 Postgresql、 Redis 等組件,所以一般有兩種途徑進行安裝:通過 Docker 或用 Python 搭建。官網下分別有以下的兩個介紹:
因為在 Github 上有一個開源項目用于部署 Sentry ,所以我們這里以Docker安裝為例。
要求:
- 服務器的內存至少 3G,否則在執行 sentry upgrade 命令時會出現問題
- Docker 19.03.6+
- Compose 1.24.1+
我們可以直接使用該項目進行部署,首先是克隆該項目:
git clone https://github.com/getsentry/onpremise.git
會看到有一個 onpremise 文件夾。后續的操作都在這個文件夾里面,如果并沒有特殊要求或者額外的組件配置的話(比如說使用已有的 Postgresql 和 redis),可以直接運行 ./install.sh 將 Sentry 及其依賴都通過 docker 安裝。
cd onpremise
# 執行安裝
./install.sh
后續一步一步安裝下來
install.png
然后你會發現 Fetching and updating Docker images 等了幾個世紀都沒反應!實在是太慢了,所以我們要改成阿里云的鏡像在執行 install 命令,到阿里云里面獲取最新的鏡像地址
https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
image.png
根據圖中的描述操作就可以替換成阿里云的鏡像。然后重新跑命令./install.sh,幾分鐘后,我們就可以按照下圖所示創建admin賬戶用來登陸本地sentry服務。
create.png
如果要自定義配置文件,推薦根據需求修改一下文件配置
- config.yml
- sentry.conf.py
- .env w/ environment variables
以下是簡單的郵件配置
Sentry 支持郵件發送的功能非常重要,當 Sentry 捕獲事件之后,可以將此捕獲的事件發送到你的個人郵箱(針對 Sentry 管理員賬號)。要修改目前的郵件配置是不能在界面上操作的,需要進行以下步驟:
修改 sentry/config.yml文件配置
###############
# Mail Server #
###############
# mail.backend: 'smtp' # Use dummy if you want to disable email entirely
mail.host: 'smtp'
mail.port: 25
mail.username: ''
mail.password: ''
mail.use-tls: false
The email address to send on behalf of
mail.from: 'root@localhost'
在docker-compose.yml 文件中加入以下配置
x-sentry-defaults: &sentry_defaults
<< : *restart_policy
build:
context: ./sentry
args:
- SENTRY_IMAGE
- SENTRY_PYTHON3
image: sentry-onpremise-local
depends_on:
- redis
- postgres
- memcached
- smtp
- snuba-api
- snuba-consumer
- snuba-outcomes-consumer
- snuba-sessions-consumer
- snuba-transactions-consumer
- snuba-replacer
- symbolicator
- kafka
environment:
...
#這里開始
SENTRY_EMAIL_HOST: #郵件host 例如smtp.qq.com
SENTRY_EMAIL_USER: #郵件地址 例如testuser@qq.com
SENTRY_EMAIL_PASSWORD: # 填寫自己的密碼
SENTRY_SERVER_EMAIL: #郵件地址
SENTRY_EMAIL_PORT: 587 # port
SENTRY_EMAIL_USE_TLS: 'true'
修改完以上配置后run ./install.sh
啟動sentry
待./install.sh結束后,run docker-compose up -d 即可啟動本地的sentry服務,你將看到以下登陸界面。
image.png
使用已經建立的admin user登陸即可,如果run ./install.sh 過程中我們沒有創建用戶,接下來我們可以run docker-compose run --rm web createuser 創建用戶。
然后可以測試一下郵件發送。登陸超級用戶下點擊左上角頭像選擇 Admin 進入到管理員界面,選擇 mail(郵箱)菜單,看到更新后的郵箱設置:
image.png
點擊最下方的 發送測試郵件 到當前用戶的郵箱上,即可測試郵件發送功能是否配置成功。
3.官方Sentry服務
如果要使用官方的Sentry服務,我們只需去它的官網注冊就行,一般是配合企業用戶使用的付費模式。
image.png
4.簡單的使用
1. 創建project
- 登錄Sentry組織
- 選擇
Projects
從左側導航菜單中顯示的所有項目名單 - 點擊
+ Create Project
按鈕
image.png
根據您要監視的代碼為您的項目選擇語言或框架,在這種情況下為JavaScript。
- 給項目一個Name。
- 正在Set your default alert settings檢查中i'll create my own alerts later
- Assign a Team 到項目。
image.png
4.復制DSN key和方便使用,因為我們會將密鑰復制到源代碼中。
image.png
2.創建Alert
為每個項目創建各種警報規則,并在應用程序中發生錯誤時讓Sentry通知何時,如何以及要通知誰。警報規則由“條件”和“操作”組成,它們在滿足相關條件時執行。有關更多信息,請參閱警報。創建新項目時,可以選擇使用警報規則創建該項目,該規則將在第一次出現新問題時(通過電子郵件)通知所有項目團隊成員。這意味著下次發生類似錯誤時,由于錯誤不是“新的”,因此不會觸發通知。
1.單擊Alerts以打開“警報配置”頁面
2.點擊 New Alert Rule
image.png
3.在“新警報規則”表單中,選擇一種Issue Alert類型并輸入以下值
image.png
每當在“所有環境”中通過郵件看到事件時,新的警報規則就會通知選定的團隊成員
4.點擊Save Rule創建新規則
3.將Sentry SDK引入前端代碼
- 在GitHub上打開
frontend-monitoring
示例代碼存儲庫 - 單擊
Fork
并選擇您希望將此存儲庫分支到的目標GitHub帳戶 - 派生完成后,單擊Clone or download,然后復制存儲庫HTTPS URL
- 克隆項目到本地
git clone <repository HTTPS url>
5.安裝SDK
Sentry通過在應用程序運行時中使用特定于平臺的SDK捕獲數據。要使用SDK,需要在源代碼中導入并配置它。該演示項目使用React和Browser JS。最快的入門方法是使用CDN托管版本的JavaScript瀏覽器SDK,也可以NPM安裝瀏覽器SDK。
- 打開index.html文件(位于./frontend-monitoring/public/下)
- 在Sentry SDK配置中,輸入DSN從上一節中創建的項目中復制的鍵值
Sentry.init({
dsn: "<PASTE YOUR DSN KEY HERE>",
});
- 啟動應用
1.打開一個shell終端,并將目錄更改為frontend-monitoring項目文件夾
2.使用該.nvmrc文件來設置與此項目兼容的Node版本。跑:
3.通過運行以下命令安裝項目依賴項:> nvm use
4.通過運行以下命令在本地主機上構建,部署和運行項目> npm install
> npm run deploy
image.png
部署成功完成后,您將在終端中看到確認信息。
5.React集成
因為Sentry使用的是一種Hook錯誤函數的技術,來達到捕獲錯誤的目的,所以我們基本可以無損耗的接入到現有的項目中去。
下面是React與Sentry進行結合的核心代碼
- 自定義錯誤捕獲的組件
#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;
}
}
- 配置客戶端 (https://github.com/getsentry/sentry-javascript#other-packages)
這里我們配置Raven.js以使用Sentry DS
#index.js
Raven.config("DSN", {
release: release,
}).install();
ReactDOM.render(
<div>
<SentryBoundary>
<App />
</SentryBoundary>
</div>,
document.getElementById("root")
);
Raven.js支持所有主要的瀏覽器。在較舊的瀏覽器中,Raven.js收集的錯誤報告的詳細程度可能會降低–例如,缺少堆棧跟蹤數據或缺少源代碼列號。
image.png
- 上傳source-map
如果上面的代碼已經配置好后,那么現在的應用是可以捕獲到錯誤的,但是存在了一個問題,我們目前的項目大多都使用webpack
進行打包,而打包后的代碼是混淆加密的代碼,無法讓我們準確的知道拋出錯誤的位置在哪里。所以我們需要上傳source-map
和混淆后的文件一起上傳到Sentry
服務器上。方便我們快速查找到問題所在的位置。
這個上傳的配置及命令是比較繁瑣的。也是項目結合Sentry
的一個難點。
上傳source-map
目前有兩種方式:
1.使用Sentry
提供的Webpack
插件進行配置,但是其靈活性不高。
Sentry提供了一個方便的Webpack插件,該插件可配置源地圖并將其在構建過程中上載到Sentry。建議使用此過程將源上傳到Sentry:
初始化插件時僅綁定必需的參數:npm install --save-dev @sentry/webpack-plugin
2.使用const SentryWebpackPlugin = require("@sentry/webpack-plugin"); module.exports = { // other configuration configureWebpack: { plugins: [ new SentryWebpackPlugin({ // sentry-cli configuration authToken: process.env.SENTRY_AUTH_TOKEN, org: "exmaple-org", project: "example-project", // webpack specific configuration include: ".", ignore: ["node_modules", "webpack.config.js"], }), ], }, };
sentry-cli
的,其靈活性比較高,可以針對不同項目進行單獨的配置。
其配置較為繁瑣,具體的React與Sentry結合的例子。可見參見github上的項目: react-sentry-demo。對每個配置都有詳細的說明。其中的上傳source-map
,實現了: 打包、環境檢測、認證檢測、上傳source-map、刪除本地source-map的操作,完成自動化,可以把腳本直接遷移到現有的項目中去,改動也不會太大。
其核心上傳命令如下:sentry-cli releases files <release_name> upload-sourcemaps /path/to/files
6.淺入原理
在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服務端,進行錯誤信息展示。
從上面的淺入原理可以看到,其核心捕獲是window.onerror。那么只要它可以捕獲到的錯誤,都會發送到Sentry上。而window.onerror能捕獲到的錯誤,除了Promise,基本上能在控制臺出現的錯誤,都會捕獲到。也就是運行時的錯誤,包括語法錯誤。