前端团队的守护者:探索 Sentry 监控的威力

3,348 阅读8分钟

原创 陈嘉伟 / 叫叫技术团队

前言

在当今快节奏的前端开发世界中,错误和异常是不可避免的挑战。为了确保我们的应用程序始终保持稳定和高质量,我们需要一种可靠的监控方案。而 Sentry 监控正是为前端团队提供了这样的守护者角色。 本文将带你深入了解 Sentry 监控的强大功能,我们将探讨如何集成和配置 Sentry 监控,以及如何利用其捕获、追踪和处理前端错误和异常的能力。 通过使用 Sentry 监控,你将能够快速定位和解决前端问题,提高应用程序的稳定性和用户体验。无论你是开发者还是团队负责人,本文都将为你提供实用的知识和建议,帮助你优化前端开发流程并提高团队的效率。 让我们开始探索 Sentry 监控的世界,成为前端团队的守护者吧。

Sentry 监控简介

Sentry 是一个 C/S 架构,我们需要在自己应用中集成 Sentry 的 SDK 才能在应用发生错误是将错误信息发送给 Sentry 服务端。根据语言和框架的不同,我们可以选择自动或自定义设置特殊的错误类型报告给 Sentry 服务端。 Sentry 的服务端分为 web、replay、snuba、worker 这几个部分,应用(客户端)发生错误后将错误信息上报给web,web 处理后放入消息队列或 Redis 内存队列,worker 从队列中消费数据进行处理。 image.png

Sentry 支持自动收集和手动收集两种错误收集方法;我们能成功监控到 Vue 中的错误、异常,但是还不能捕捉到异步操作、接口请求中的错误,比如接口返回404、500等信息,此时我们可以通过 Sentry.caputureException()进行主动上报。 image.png

安装 Sentry 监控

自托管部署 Sentry 服务

Docker 部署

官方教程:develop.sentry.dev/self-hosted…

  1. 在本地安装 Docker 环境参考: docs.docker.com/get-docker/
  2. 下载 Sentry 最新的安装包:github.com/getsentry/s…
  3. 在安装包目录下执行命令 ./install.sh 该脚本会处理所有需要安装的配置。
  4. 安装完成后使用 Docker 命令启动 docker-compose up -d Sentry 默认启动端口9000本地可以访问http://127.0.0.1:9000

添加Sentry监控

创建项目

image.png

创建完成后,能够看到相应的 SDK 接入提示: image.png

SDK 安装

Sentry 的 SDK 支持多种不同的框架和语言,这里选择其中一种详细讲解,如需了解其他的可以查看官方文档image.png 这里选用 Vue2.0 项目作为深入的了解。

初始化 SDK

安装 Vue 框架的 Sentry SDK:

npm install --save @sentry/vue
import Vue from "vue";
import Router from "vue-router";
import * as Sentry from "@sentry/vue";

Vue.use(Router);

const router = new Router({
  // ...
});

Sentry.init({
  Vue,
  dsn: "http://619a0e82d62a4a249b1c76f5e4a91c59@127.0.0.1:9000/4",
  integrations: [
    new Sentry.BrowserTracing({
      // Set `tracePropagationTargets` to control for which URLs distributed tracing should be enabled
      tracePropagationTargets: ["localhost", /^https:\/\/yourserver\.io\/api/],
      routingInstrumentation: Sentry.vueRouterInstrumentation(router),
    }),
  ],
  // Set tracesSampleRate to 1.0 to capture 100%
  // of transactions for performance monitoring.
  // We recommend adjusting this value in production
  tracesSampleRate: 1.0,
});

// ...

new Vue({
  router,
  render: (h) => h(App),
}).$mount("#app");

SDK 常用参数

讲解部分配置,其他不在这里赘述,详细参考:官方文档

  • dsn:项目地址,用于收集错误信息的 Sentry 分配的地址;
  • debug:是否开启 debug 模式,开启 debug,就会把信息打印到控制台上面;
  • release:代码的版本号,可以确定当前的错误/异常属于哪一个发布的版本,可以应用到 sourcemaps 来映射源码;
  • environment:环境名称;
  • sampleRate:是否开启随机发送事件给 Sentry ,1为100%,0.1为10%几率发送事件;
  • attachStacktrace:是否开启堆栈跟踪,开启后跟着消息一起收集;
  • beforeSend:发送前操作;

SDK API

  • captureException(exception):捕获一个 js 异常,传入一个 exception 对象或者类对象;
  • captureMessage(message,level):捕获一条信息,传入信息内容和信息级别;
  • captureEvent(sentryEvent):捕获一个事件,sentryEvent 是手动创建的,自定义的;
  • addBreadcrumb(Breadcrumb):添加一个面包屑,以供接下里的捕获;
  • configureScope((scope)=>{}):全局配置:设置 context 信息到 scope 上面;
  • withScope((scope)=>{}):设置一个临时的 scope 信息到 context 上面,只适用于当前范围内捕获的事件;
Sentry.withScope(function (scope) {
  scope.addEventProcessor(function (event, hint) {
    // Add anything to the event here
    // returning `null` will drop the event
    return event;
  });
  // The event processor will apply to this event
  Sentry.captureMessage("Test");
});

context 上下文信息

讲解部分配置,详细参考:官方文档

上下文信息包括:user、tags、level、fingerprint、extra data。 这些信息我们可以通过在 scope 上面设置来定义。 其中可以通过两种方法得到 scope:

// 将 scope 配置到 context 上面
Sentry.configureScope((scope) => { }); 

// 创建一个临时到 scope ,配置到 context 上面
Sentry.withScope((scope) => { });

User

讲解部分配置,详细参考:官方文档

scope.setUser({
  id: "1" ,
  username: "xiao" ,
  ip_address: "{{auto}}" ,
  email: "test.doe@example.com" ,
});

通过 setUser 来设置 User 信息。 其中 User 可以设置的信息包括 id、username、ip_address、email。 :::info 如果用户的 ip_address 设置为 "{{auto}}" ,Sentry 将从您的应用程序和 Sentry 服务器之间的连接推断 IP 地址。 :::

Tags

讲解部分配置,详细参考:官方文档

Tags 是给事件自定义不同的键/值对,可以在查找的时候更容易。 后台查找的时候,查找选项会多出来一个选项,就是通过 tags 来设置的。

scope.setTag( "page_local" , "de-at" );

通过 setTag 来设置了一个 page_local 的标签,后台会多一个 page_local 选项。

Event Level

讲解部分配置,详细参考:官方文档

通过这个来设置事件等级。 包括:fatal、error、 warning、 info、 debug

scope.setLevel( "warning" );

通过 setLevel 来设置。

Event Fingerprint

讲解部分配置,详细参考:官方文档

所有事件都有指纹。具有相同指纹的事件被分组到一个问题中。 如果想要更好的对错误进行分组,也可以自定义指纹的分组信息。

Sentry.init({
  // ...
  beforeSend: function (event, hint) {
    const exception = hint.originalException;

    if (exception instanceof DatabaseConnectionError) {
      event.fingerprint = ['database-connection-error'];
    }

    return event;
  },
});

Extra Data 传入额外的信息,并不会创建索引(也就是不可以提供来检索)。 在最新版 Sentry 中,不推荐使用额外信息。

scope.setExtra( "character_name" , "Mighty Fighter" );

通过 setExtra 来设置。

  • 使用 Extra Data 传入的额外信息无法搜索

image.png image.png

  • 使用 Tags 可以搜索到结果

image.png image.png

添加错误堆栈追踪依赖

npx @sentry/wizard@latest -i sourcemaps

image.png webpack.config.js 配置中添加:

const { sentryWebpackPlugin } = require("@sentry/webpack-plugin");

module.exports = {
  // ... other config options
  devtool: "source-map", // Source map generation must be turned on
  plugins: [
    sentryWebpackPlugin({
      authToken: process.env.SENTRY_AUTH_TOKEN,
      org: "sentry",
      project: "demo-vue",
      url: "http://127.0.0.1:9000/",  
    }),
  ],
};

配置完成后,构建项目即可在 Sentry Web 端项目管理中看到对应项目的 sourceMap 文件。

错误捕获与追踪

Sentry 前端异常监控基本原理

错误事件捕获

1.重写 window.onerror 方法、重写 window.onunhandledrejection 方法

window.onerror = function (message, source, lineno, colno, error) {
	console.log('message, source, lineno, colno, error', message, source, lineno, colno, error);
}

参数:

  • message:错误信息(字符串)。可用于 HTML onerror="" 处理程序中的 event;
  • source:发生错误的脚本 URL(字符串);
  • lineno:发生错误的行号(数字);
  • colno:发生错误的列号(数字);
  • error:Error对象(对象);

当 Promise 被 reject 且没有 reject 处理器的时候,会触发 unhandledrejection 事件;这可能发生在 window 下,但也可能发生在 Worker 中。 这对于调试回退错误处理非常有用。

Sentry 源码可以搜索 global.onerror 定位到具体位置:

 GlobalHandlers.prototype._installGlobalOnErrorHandler = function () {
	// 代码有删减
	// 这里的 this._global 在浏览器中就是 window
	this._oldOnErrorHandler = this._global.onerror;
	this._global.onerror = function (msg, url, line, column, error) {}
	// code ...
 }

同样,可以搜索 global.onunhandledrejection 定位到具体位置:

GlobalHandlers.prototype._installGlobalOnUnhandledRejectionHandler = function () {
	// 代码有删减
	this._oldOnUnhandledRejectionHandler = this._global.onunhandledrejection;
	this._global.onunhandledrejection = function (e) {}
}

上报错误

采用Ajax上传

支持 fetch 使用 fetch,否则使用 XMLHttpRequest。

BrowserBackend.prototype._setupTransport = function () {
	// 代码有删减
	if (supportsFetch()) {
		return new FetchTransport(transportOptions);
	}
	return new XHRTransport(transportOptions);
};

fetch

FetchTransport.prototype.sendEvent = function (event) {
	var defaultOptions = {
		body: JSON.stringify(event),
		method: 'POST',
		referrerPolicy: (supportsReferrerPolicy() ? 'origin' : ''),
	};
	return this._buffer.add(global$2.fetch(this.url, defaultOptions).then(function (response) { return ({
		status: exports.Status.fromHttpCode(response.status),
	}); }));
};

XMLHttpRequest

XHRTransport.prototype.sendEvent = function (event) {
	var _this = this;
	return this._buffer.add(new SyncPromise(function (resolve, reject) {
		// 熟悉的 XMLHttpRequest
		var request = new XMLHttpRequest();
		request.onreadystatechange = function () {
			if (request.readyState !== 4) {
				return;
			}
			if (request.status === 200) {
				resolve({
					status: exports.Status.fromHttpCode(request.status),
				});
			}
			reject(request);
		};
		request.open('POST', _this.url);
		request.send(JSON.stringify(event));
	}));
}

使用 Sentry 面板进行错误追踪和分析

了解了 SDK 的错误捕获机制以及错误上报的原理,我们接下来看看如何使用 Sentry 进行错误的追踪和分析。

基本术语

  • Event:应用端每次触发异常,就是一个 Event,会上报到 Sentry 中;
  • Issue:Sentry 会对上报的异常按照一定的指纹算法进行 Group,(具体算法可以查看不同 SDK 的 Issue Group 文档,比如 Django Issue Grouping)相同的异常 Event 会被归类到一个 Issue 下;

Issues 面板

解释问题列表默认会展示当前项目所未解决问题列表,可用来搜索查找某个线上问题在 Sentry 是否有过告警的情况。 image.png

Tab(选项栏)

image.png

  • All Unresolved:所有未解决问题;
  • For Review:需要 review 的问题,此选项会列出最7天出现的新 issues 和被重新打开的 issues ;
  • ignore:已忽略的搜索;

Search(搜索框)

image.png 搜索框一般用来根据某些已知条件搜索 Sentry 中是否有上报相关信息的错误,比如已知某个线上问题工单里面的关键信息,在 Sentry 中搜索相关错误。

搜索语法

搜索查询语法是使用一种 key:value 模式构建的。每一对 key:value 都是一个 token。每个 token 可以为:

  • 一个普通的字符串,作为普通字符,搜索匹配的结果是与问题标题和正文匹配的结果:

image.png

  • 一个问题属性或者事件属性,这些都是 Sentry 内置的关键字,常见的内置关键字 tag 有:
    • href:问题发生的链接
    • os:系统信息 (iOS、Android)
    • device:设备信息(iPhone)
    • brower:浏览器信息
  • 一个自定义标签 Tag(每个项目都可以使用 Sentry.setTag 设置自定义标签)

其他高级搜索

描述事例备注
多条件联合搜索user.id: 1111
os.name: "Android 12"空格分割条件
匹配多个 valueos.name: [iOS, Android]需要注意这里的含义为:iOS 或者 Android
逻辑非 !!os.name: [Android]
通配符 *browser: "Safari 11*"

更多搜索可参考 Sentry Search

Issue 详情面板

主要由顶部面板和侧边栏组成的概览信息,以及主区域显示的详情信息组成。 image.png 在详情面板中可以看到172.18.0.1的IP地址,这个是 Sentry 标示当前采集用户的 IP 信息,在我们自己的业务当中,我们也可以自定义这个用户信息,便于我们排查问题的时候查到对应的用户。

// 自定义采集用户信息
Sentry.setUser({
  id: 业务内部的用户ID值,
  username: "用户名称",
  email: "john.doe@example.com",
  segment: "用户划分",
  ip_address: "如果用户的ip_address设置为“{{auto}}”,Sentry将从你的应用和Sentry服务器之间的连接中推断出IP地址。"
});

SideBar(侧边栏)

image.png
侧边栏记录了最近24小时、最近30天事件发生的次数;首次出现事件与最后出现时间;需要重点关注 All tags,它展示了与本次错误相关联的所有标签分布,以及占比。比如最近30天次错误发生了150次,tag:Mobile Safari 13.0.3 占比为100%,则应考虑是否为此 iOS 系统版本兼容性问题。

Tags(标签)

image.png 除了 Sentry 默认采集的一些通用标签之外,我们还可以自定义一些标签,能够有助于我们更快的识别问题。

// 自定义标签 标签名称、标签值
Sentry.setTag("page_name", "test-page");

Exception(Stack Trace)(堆栈跟踪)

显示事件出错的代码行(需要先接入 sourceMap)。 image.png

Breadcrumbs(面包屑)

面包屑列表分别展示了:类型、类别、描述、等级、时间等信息,时间排序为倒序。点击时间可以切换为相对时间。接入用户回放功能后还会显示用户回放的入口信息。提供导致错误事件的历史记录和时间线,查看问题发生之前的一些其他轨迹。

be9d9636af71bb72bec8aee804713a73.png 通过对 Issue 面板的使用,我们能够了解到一个错误发生的前后状态的变化,也能够通过面包屑知道用户的那一些交互行为触发了错误事件,便于我们能够快速的定位和复现问题。

异常告警

Sentry 也提供了异常告警通知,正确的配置告警能够让我们及时发现系统的错误并解决。 image.png

image.png 规则设置:

  • An event is seen: 一个事件发生的时候;
  • An issue is first seen: 第一个发生错误的时候;
  • An issue changes state from resolved to unresolved:问题从解决到未解决的时候;
  • An event’s tags match {key} {match} {value}: 匹配到 tags 的键值对的时候发送;
  • An issue is seen more than {value} times in {interval}:在固定时间内出现次数匹配的时候;
  • An issue is seen by more than {value} users in {interval}:在固定时间内出现用户的次数匹配的时候;
  • An event’s {attribute} value {match} {value}: 匹配到某一个事件的时候;
  • An event’s level is {match} {level}: 事件级别匹配的时候;

Sentry 默认是以邮件的形式发送通知给被通知人员,如果觉得邮件没办法及时看到通知消息,也可以使用 Sentry 的 Webhook 集成类似于钉钉这种办公工具,能够通过钉钉发送指定的消息给对应的人员。

总结

Sentry 监控在前端开发中扮演着重要的角色。它提供实时错误监测、错误定位调试和数据分析等功能,帮助团队快速发现和解决应用程序中的问题,提升应用稳定性和用户体验。通过自动化的告警和通知机制,Sentry 监控确保团队能够及时响应关键问题,并促进团队协作和知识共享。总的来说,Sentry 监控是一种强大的工具,为前端团队提供了洞察力和能力,提高应用程序开发质量。
每一次错误排查都加深了我们对 Sentry 功能的理解,通过 Sentry,我们能够捕获并解决隐藏在应用程序中的潜在问题,保障应用的质量和稳定性。
问题不可避免,但在 Sentry 的护航下,我们能够更好地成长。