sentry - Sentry 错误上报集成
本模块用于集成 Sentry 错误监控服务,自动捕获应用运行时异常并上报至 Sentry 平台。
当请求处理过程中发生异常时,模块会自动附带请求上下文信息(如请求路径、Header、客户端 IP 等)一同上报,便于快速定位问题。
安装
npm install @zenweb/sentry
配置
模块配置项继承自 @sentry/node 的 NodeOptions,所有 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();
工作原理
模块在初始化时会做以下事情:
- 调用
@sentry/node的init()方法完成 Sentry SDK 初始化 - 监听 Koa 的
error事件,自动捕获所有运行时异常 - 对于带有请求上下文(
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);
});
}
}
}