跳到主要内容

sentry - Sentry 错误上报集成

本模块用于集成 Sentry 错误监控服务,自动捕获应用运行时异常并上报至 Sentry 平台。

当请求处理过程中发生异常时,模块会自动附带请求上下文信息(如请求路径、Header、客户端 IP 等)一同上报,便于快速定位问题。

安装

npm install @zenweb/sentry

配置

模块配置项继承自 @sentry/nodeNodeOptions,所有 Sentry 原生配置均可直接使用。

src/index.ts

src/index.ts
import { create } from 'zenweb';
import sentry from '@zenweb/sentry';

create()

.setup(sentry({
// Sentry DSN,在 Sentry 项目设置中获取
dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',

// 运行环境标识,用于在 Sentry 中区分不同环境
environment: process.env.NODE_ENV || 'development',

// 发布版本号,用于关联代码版本
release: process.env.APP_VERSION || '1.0.0',

// 性能追踪采样率(0.0 ~ 1.0)
tracesSampleRate: 0.2,

// 发送前回调,可对事件进行过滤或修改
beforeSend(event) {
// 可在此过滤敏感信息
return event;
},
}))

.start();

工作原理

模块在初始化时会做以下事情:

  1. 调用 @sentry/nodeinit() 方法完成 Sentry SDK 初始化
  2. 监听 Koa 的 error 事件,自动捕获所有运行时异常
  3. 对于带有请求上下文(ctx)的异常,自动附加请求信息并上报

自动捕获的错误信息

当请求过程中发生异常时,上报内容包含:

信息说明
请求路径当前请求的 URL
请求方法GET / POST / PUT 等
请求头所有请求头信息
请求数据Query 参数和 Body 数据
客户端 IP请求来源 IP
Request ID请求头 x-request-id 的值(如存在)

使用示例

基础用法

安装模块后,所有未捕获的异常都会自动上报到 Sentry,无需额外代码。

src/index.ts
import { create } from 'zenweb';
import sentry from '@zenweb/sentry';

create()
.setup(sentry({
dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0',
environment: 'production',
tracesSampleRate: 0.1,
}))
.start();

控制器中抛出的异常

src/controller/user.ts
import { Get, Context } from 'zenweb';

export class UserController {
@Get()
async info(ctx: Context) {
const user = await findUser(ctx.query.id);
if (!user) {
// 抛出的异常会被自动上报到 Sentry
throw new Error('用户不存在');
}
return user;
}
}

手动上报异常

在某些场景下,可能需要手动捕获并上报异常,而不中断请求流程。

src/service/payment.ts
import * as Sentry from '@sentry/node';

export class PaymentService {
async process(orderId: string) {
try {
await this.doPayment(orderId);
} catch (err) {
// 手动上报异常,但不中断流程
Sentry.captureException(err);
// 降级处理
await this.markOrderFailed(orderId);
}
}
}
提示

手动上报时使用 @sentry/node 直接导出的 captureException 方法即可,无需额外配置。

添加自定义上下文标签

可以通过 withScope 为特定错误附加额外信息。

src/service/order.ts
import { withScope, captureException } from '@sentry/node';

export class OrderService {
async processOrder(orderId: string) {
try {
await this.handleOrder(orderId);
} catch (err) {
withScope(scope => {
scope.setTag('order_id', orderId);
scope.setExtra('order_data', { orderId, timestamp: Date.now() });
captureException(err);
});
}
}
}