Angular Sentry前端错误监控

本教程主要讲述, Angular 项目如何整合 Sentry 实现前端应用错误上报.

1. 什么是 Sentry

sentry 是一个基于 Django 构建的现代化的实时事件日志监控、记录和聚合平台,主要用于如何快速的发现故障。支持几乎所有主流开发语言和平台,并提供了现代化 UI,它专门用于监视错误和提取执行适当的事后操作所需的所有信息,而无需使用标准用户反馈循环的任何麻烦。官方提供了多个语言的 SDK.让开发者第一时间获悉错误信息,并方便的整合进自己和团队的工作流中.官方提供 saas 版本免费版支持每天 5000 个 event.

sentry 支持自动收集和手动收集两种错误收集方法.我们能成功监控到 vue 中的错误、异常,但是还不能捕捉到异步操作、接口请求中的错误,比如接口返回 404、500 等信息,此时我们可以通过 Sentry.caputureException()进行主动上报。使用 sentry 需要结合两个部分,客户端与 sentry 服务端;客户端就像你需要去监听的对象,比如公司的前端项目,而服务端就是给你展示已搜集的错误信息,项目管理,组员等功能的一个服务平台。

这个平台可以自己搭建,也可以直接使用 sentry 提供的平台(注册可用),当然如果是公司项目,当然推荐自己搭建.

2. 什么是 DSN?

DSN 是连接客户端(项目)与 sentry 服务端,让两者能够通信的钥匙;每当我们在 sentry 服务端创建一个新的项目,都会得到一个独一无二的 DSN,也就是密钥。在客户端初始化时会用到这个密钥,这样客户端报错,服务端就能抓到你对应项目的错误了。之前版本的 sentry 对于密钥分为公钥和私钥,一般前端用公钥(DSN(Public)),但是现在的版本舍弃了这种概念,只提供了一个密钥。

3. 什么是 event

每当项目产生一个错误,sentry 服务端日志就会产生一个 event,记录此次报错的具体信息。一个错误,对应一个 event。

4. 什么是 issue

同一类 event 的集合,一个错误可能会重复产生多次,sentry 服务端会将这些错误聚集在一起,那么这个集合就是一个 issue。

5. Angular 项目中使用 Sentry

5.1. 注册 sentry,本文示例采用 Self-hosted 版

关于搭建 Sentry 可以参考我的博客 - 如何在 Ubuntu 22.04 上用 Docker 安装 Sentry.

登录到 sentry

  1. 选择创建项目

  2. Chose your platform

    • 项目类型选择 Angular
  3. Set your alert frequency

    • 根据实际情况选择
  4. Name your project and assign it a team

    • 给项目设置一个名称, 并分配给 team

创建成功后, 会弹出提示关于 Angular sentry SDK 的指引提示框, 如果不小心关闭了提示框, 里面的一些关机信息可以到 Settings=>Projects 中找到.

5.2. 配置 Angular sentry SDK

创建完项目后, 系统会会给出安装 Angular sentry SDK 的指引, 安装指引进行配置.

以下是参考配置指引列出的步骤, 本文只讲解针对 Angular 12 以上版本的配置方法, 对于低于 Angular 12 的 Angular 项目, 可以参考安装指引进行配置.

5.3. 安装依赖包

1
2
3
4
5
6
7

npm install --save @sentry/angular-ivy

# 或者

yarn add @sentry/angular-ivy

5.4. 配置 SDK

在应用程序加载期间,在初始化 Angular 之前,您应该尽快在 main.ts 文件中初始化 Sentry 浏览器 SDK:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import * as Sentry from "@sentry/angular-ivy";

import { AppModule } from "./app/app.module";

Sentry.init({
dsn: "your_dsn_get_from_sentry_project_configuration",
integrations: [
new Sentry.BrowserTracing({
// Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled
tracePropagationTargets: [],
routingInstrumentation: Sentry.routingInstrumentation,
}),
new Sentry.Replay(),
],
// Performance Monitoring
tracesSampleRate: 1.0, // Capture 100% of the transactions
// Session Replay
replaysSessionSampleRate: 0.01, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
});

enableProdMode();
platformBrowserDynamic()
.bootstrapModule(AppModule)
.then((success) => console.log('Bootstrap success'))
.catch((err) => console.error(err));

Sentry Angular SDK 导出一个函数来实例化 ErrorHandler 提供程序,该提供程序将自动发送 Angular 错误处理程序捕获的 JavaScript 错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { APP_INITIALIZER, ErrorHandler, NgModule } from "@angular/core";
import { Router } from "@angular/router";
import * as Sentry from "@sentry/angular-ivy";

@NgModule({
// ...
providers: [
{
provide: ErrorHandler,
useValue: Sentry.createErrorHandler({
showDialog: true,
}),
},
{
provide: Sentry.TraceService,
deps: [Router],
},
{
provide: APP_INITIALIZER,
useFactory: () => () => {},
deps: [Sentry.TraceService],
multi: true,
},
],
// ...
})
export class AppModule {}

5.5. 上传 Source Maps

自动上传 Source Maps 以启用可读的堆栈跟踪错误。如果您喜欢手动设置源地图,请遵循本指南

最简单的办法是

1
2
npm install -g @sentry/wizard
sentry-wizard

6. 收集用户反馈

除了自动上报异常, Sentry 也可以用来主动收集用户的意见和建议, 而不必另外开发一套反馈程序. 可视化部分可以借助 Sentry 的管理界面, 非常省事.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

import * as Sentry from '@sentry/browser'

sendUserFeedback() {
//
const eventId = Sentry.captureMessage('User Feedback')

const userFeedback = {
event_id: eventId,
name: 'John Doe',
email: 'john@doe.com',
comments: 'I really like your App, thanks!',
}
Sentry.captureUserFeedback(userFeedback)
}

实现 sendUserFeedback, 将其绑定在定制的反馈界面的提交按钮的点击事件上. 配置过程参考上面讲到的配置 SDK

7. Verify

以下代码片段包含一个故意的错误,可以用作测试,以确保一切正常。

1
myUndefinedFunction();

8. Trouble shooting

issue 1: 首次开启访问遇到 CORS is not allowed 问题

1
2
3
4
5

Access to XMLHttpRequest at 'http://localhost:8888' from origin 'http://localhost:4200' has been blocked by CORS policy: Request header field baggage is not allowed by Access-Control-Allow-Headers in preflight response.
instrument.js:123 an error happened when posting to apiServer HttpErrorResponse {headers: HttpHeaders, status: 0, statusText: 'Unknown Error', url: 'http://localhost:8888', ok: false, …}error: ProgressEvent {isTrusted: true, lengthComputable: false, loaded: 0, total: 0, type: 'error', …}headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, headers: Map(0)}message: "Http failure response for http://localhost:8888 0 Unknown Error"name: "HttpErrorResponse"ok: falsestatus: 0statusText: "Unknown Error"url: "http://api_server"[[Prototype]]: HttpResponseBase
zone.js:2645

  • 分析 1: 原因是由于 tracePropagationTargets: ["localhost", /^https:\/\/yourserver\.io\/api/] 配置了 localhost, sentry sdk 捕获到请求, 在请求头添加了 sentry-trace 和 baggage 两个字段, 此字段不被服务器端接受, 所以拒绝了.

  • 解决办法有两种:

      1. 如果没有分布式跟踪错误请求的需要, 可以在 sentry 配置中将 tracePropagationTargets 设置为空数组tracePropagationTargets: []
      1. 如果需要跟踪错误的请求, 需要在服务器端 Access-Control-Allow-Headers 配置中添加 sentry-trace, baggage 字段.

对于解决办法 1: 可以参考https://stackoverflow.com/questions/71804069/sentry-get-cors-error-in-localhost-by-vuejs3

对于解决方案 2: 可以参考https://docs.sentry.io/platforms/javascript/guides/nextjs/usage/distributed-tracing/dealing-with-cors-issues/

issue 2: 开启SSR(服务器端渲染)后在日志中看到很多这样的错误”ErrorEvent is not defined”。

1
2
3
4
5
6
7
8
9
10
11
12
13

ReferenceError: ErrorEvent is not defined
at extractHttpModuleError (node_modules/@sentry/angular-ivy/fesm2015/sentry-angular-ivy.js:101:32)
at SentryErrorHandler._defaultExtractor (node_modules/@sentry/angular-ivy/fesm2015/sentry-angular-ivy.js:187:20)
at SentryErrorHandler._extractError (node_modules/@sentry/angular-ivy/fesm2015/sentry-angular-ivy.js:178:21)
at SentryErrorHandler.handleError (node_modules/@sentry/angular-ivy/fesm2015/sentry-angular-ivy.js:135:37)
at Object.apply [as next] (node_modules/@angular/core/fesm2022/core.mjs:28159:42)
at Object.next (node_modules/rxjs/dist/cjs/internal/Subscriber.js:161:21)
at SafeSubscriber._next (node_modules/rxjs/dist/cjs/internal/Subscriber.js:101:26)
at SafeSubscriber.next (node_modules/rxjs/dist/cjs/internal/Subscriber.js:72:18)
at cb (node_modules/rxjs/dist/cjs/internal/Subject.js:66:34)
at Object.errorContext (node_modules/rxjs/dist/cjs/internal/util/errorContext.js:22:9)

原因分析:

正如您所知,当使用angular universal (Angular 17以前)或者 Angular SSR(Angular 17以后)开启时,您的页面可能是在服务器端预先渲染的。在服务器端,您将无法访问一些常见的浏览器元素,如窗口或文档等等。Sentry正在访问一些“违禁”物品。所以你需要做一些额外的努力。首先创建一个可注入类,该类仅在浏览器中运行时初始化sentry。

解决办法:

思路,首先创建一个可注入类,该类仅在浏览器中运行时初始化sentry。

9. Angular 系列文章

最新更新以及更多 Angular 相关文章请访问 Angular 合集 | 鹏叔的技术博客

10. 参考文档

Sentry Angular

Sentry 介绍与使用

Setup sentry application monitoring in an angular universal project