sentry-nestjs-sdk
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAll Skills > SDK Setup > NestJS SDK
所有技能 > SDK设置 > NestJS SDK
Sentry NestJS SDK
Sentry NestJS SDK
Opinionated wizard that scans your NestJS project and guides you through complete Sentry setup.
该向导内置最佳实践,可扫描你的NestJS项目,引导你完成Sentry的完整配置流程。
Invoke This Skill When
何时调用该技能
- User asks to "add Sentry to NestJS" or "setup Sentry" in a NestJS app
- User wants error monitoring, tracing, profiling, logging, metrics, or crons in NestJS
- User mentions or Sentry + NestJS
@sentry/nestjs - User wants to monitor NestJS controllers, services, guards, microservices, or background jobs
Note: SDK versions and APIs below reflect10.x (NestJS 8–11 supported). Always verify against docs.sentry.io/platforms/node/guides/nestjs/ before implementing.@sentry/nestjs
- 用户要求“为NestJS添加Sentry”或在NestJS应用中“配置Sentry”
- 用户需要为NestJS配置错误监控、链路追踪、性能分析、日志记录、指标监控或定时任务监控
- 用户提及或Sentry + NestJS相关内容
@sentry/nestjs - 用户想要监控NestJS控制器、服务、守卫、微服务或后台任务
注意: 下方的SDK版本和API对应10.x(支持NestJS 8–11)。 实现前请务必查阅docs.sentry.io/platforms/node/guides/nestjs/确认最新内容。@sentry/nestjs
Phase 1: Detect
阶段1:项目检测
Run these commands to understand the project before making recommendations:
bash
undefined在给出建议前,运行以下命令了解项目情况:
bash
undefinedConfirm NestJS project
Confirm NestJS project
grep -E '"@nestjs/core"' package.json 2>/dev/null
grep -E '"@nestjs/core"' package.json 2>/dev/null
Check NestJS version
Check NestJS version
node -e "console.log(require('./node_modules/@nestjs/core/package.json').version)" 2>/dev/null
node -e "console.log(require('./node_modules/@nestjs/core/package.json').version)" 2>/dev/null
Check existing Sentry
Check existing Sentry
grep -i sentry package.json 2>/dev/null
ls src/instrument.ts 2>/dev/null
grep -r "Sentry.init|@sentry" src/main.ts src/instrument.ts 2>/dev/null
grep -i sentry package.json 2>/dev/null
ls src/instrument.ts 2>/dev/null
grep -r "Sentry.init\|@sentry" src/main.ts src/instrument.ts 2>/dev/null
Check for existing Sentry DI wrapper (common in enterprise NestJS)
Check for existing Sentry DI wrapper (common in enterprise NestJS)
grep -rE "SENTRY.*TOKEN|SentryProxy|SentryService" src/ libs/ 2>/dev/null
grep -rE "SENTRY.*TOKEN|SentryProxy|SentryService" src/ libs/ 2>/dev/null
Check for config-class-based init (vs env-var-based)
Check for config-class-based init (vs env-var-based)
grep -rE "class SentryConfig|SentryConfig" src/ libs/ 2>/dev/null
grep -rE "class SentryConfig|SentryConfig" src/ libs/ 2>/dev/null
Check if SentryModule.forRoot() is already registered in a shared module
Check if SentryModule.forRoot() is already registered in a shared module
grep -rE "SentryModule.forRoot|SentryProxyModule" src/ libs/ 2>/dev/null
grep -rE "SentryModule\.forRoot|SentryProxyModule" src/ libs/ 2>/dev/null
Detect HTTP adapter (default is Express)
Detect HTTP adapter (default is Express)
grep -E "FastifyAdapter|@nestjs/platform-fastify" package.json src/main.ts 2>/dev/null
grep -E "FastifyAdapter|@nestjs/platform-fastify" package.json src/main.ts 2>/dev/null
Detect GraphQL
Detect GraphQL
grep -E '"@nestjs/graphql"|"apollo-server"' package.json 2>/dev/null
grep -E '"@nestjs/graphql"|"apollo-server"' package.json 2>/dev/null
Detect microservices
Detect microservices
grep '"@nestjs/microservices"' package.json 2>/dev/null
grep '"@nestjs/microservices"' package.json 2>/dev/null
Detect WebSockets
Detect WebSockets
grep -E '"@nestjs/websockets"|"socket.io"' package.json 2>/dev/null
grep -E '"@nestjs/websockets"|"socket.io"' package.json 2>/dev/null
Detect task queues / scheduled jobs
Detect task queues / scheduled jobs
grep -E '"@nestjs/bull"|"@nestjs/bullmq"|"@nestjs/schedule"|"bullmq"|"bull"' package.json 2>/dev/null
grep -E '"@nestjs/bull"|"@nestjs/bullmq"|"@nestjs/schedule"|"bullmq"|"bull"' package.json 2>/dev/null
Detect databases
Detect databases
grep -E '"@prisma/client"|"typeorm"|"mongoose"|"pg"|"mysql2"' package.json 2>/dev/null
grep -E '"@prisma/client"|"typeorm"|"mongoose"|"pg"|"mysql2"' package.json 2>/dev/null
Detect AI libraries
Detect AI libraries
grep -E '"openai"|"@anthropic-ai"|"langchain"|"@langchain"|"@google/generative-ai"|"ai"' package.json 2>/dev/null
grep -E '"openai"|"@anthropic-ai"|"langchain"|"@langchain"|"@google/generative-ai"|"ai"' package.json 2>/dev/null
Check for companion frontend
Check for companion frontend
ls -d ../frontend ../web ../client ../ui 2>/dev/null
**What to note:**
- Is `@sentry/nestjs` already installed? If yes, check if `instrument.ts` exists and `Sentry.init()` is called — may just need feature config.
- **Sentry DI wrapper detected?** → The project wraps Sentry behind a DI token (e.g. `SENTRY_PROXY_TOKEN`) for testability. Use the injected proxy for all runtime Sentry calls (`startSpan`, `captureException`, `withIsolationScope`) instead of importing `@sentry/nestjs` directly in controllers, services, and processors. Only `instrument.ts` should import `@sentry/nestjs` directly.
- **Config class detected?** → The project uses a typed config class for `Sentry.init()` options (e.g. loaded from YAML or `@nestjs/config`). Any new SDK options must be added to the config type — do not hardcode values that should be configurable per environment.
- **`SentryModule.forRoot()` already registered?** → If it's in a shared module (e.g. a Sentry proxy module), do not add it again in `AppModule` — this causes duplicate interceptor registration.
- Express (default) or Fastify adapter? Express is fully supported; Fastify works but has known edge cases.
- GraphQL detected? → `SentryGlobalFilter` handles it natively.
- Microservices detected? → Recommend RPC exception filter.
- Task queues / `@nestjs/schedule`? → Recommend crons.
- AI libraries? → Auto-instrumented, zero config.
- Prisma? → Requires manual `prismaIntegration()`.
- Companion frontend? → Triggers Phase 4 cross-link.
---ls -d ../frontend ../web ../client ../ui 2>/dev/null
**需要注意的要点:**
- 是否已安装`@sentry/nestjs`?如果已安装,检查是否存在`instrument.ts`以及是否调用了`Sentry.init()`——可能只需要配置功能即可。
- **检测到Sentry DI封装?** → 项目通过DI token(例如`SENTRY_PROXY_TOKEN`)封装了Sentry以提升可测试性。所有运行时的Sentry调用(`startSpan`、`captureException`、`withIsolationScope`)都应该使用注入的封装实例,不要在控制器、服务和处理器中直接导入`@sentry/nestjs`。只有`instrument.ts`可以直接导入`@sentry/nestjs`。
- **检测到配置类?** → 项目使用类型化配置类来加载`Sentry.init()`选项(例如从YAML或`@nestjs/config`加载)。所有新的SDK选项必须添加到配置类型中——不要硬编码应该按环境配置的值。
- **已注册`SentryModule.forRoot()`?** → 如果它已经在共享模块(例如Sentry代理模块)中注册,不要在`AppModule`中重复添加——这会导致拦截器重复注册。
- 使用的是Express(默认)还是Fastify适配器?Express已完全支持;Fastify可用但存在已知的边缘问题。
- 检测到GraphQL?→ `SentryGlobalFilter`原生支持。
- 检测到微服务?→ 建议使用RPC异常过滤器。
- 检测到任务队列/`@nestjs/schedule`?→ 建议使用定时任务监控。
- 检测到AI库?→ 自动埋点,无需额外配置。
- 检测到Prisma?→ 需要手动添加`prismaIntegration()`。
- 存在配套前端?→ 触发阶段4的交叉推荐。
---Phase 2: Recommend
阶段2:方案推荐
Based on what you found, present a concrete proposal. Don't ask open-ended questions — lead with a recommendation:
Always recommended (core coverage):
- ✅ Error Monitoring — captures unhandled exceptions across HTTP, GraphQL, RPC, and WebSocket contexts
- ✅ Tracing — auto-instruments middleware, guards, pipes, interceptors, filters, and route handlers
Recommend when detected:
- ✅ Profiling — production apps where CPU performance matters ()
@sentry/profiling-node - ✅ Logging — structured Sentry Logs + optional console capture
- ✅ Crons — , Bull, or BullMQ detected
@nestjs/schedule - ✅ Metrics — business KPIs or SLO tracking
- ✅ AI Monitoring — OpenAI/Anthropic/LangChain/etc. detected (auto-instrumented, zero config)
Recommendation matrix:
| Feature | Recommend when... | Reference |
|---|---|---|
| Error Monitoring | Always — non-negotiable baseline | |
| Tracing | Always — NestJS lifecycle is auto-instrumented | |
| Profiling | Production + CPU-sensitive workloads | |
| Logging | Always; enhanced for structured log aggregation | |
| Metrics | Custom business KPIs or SLO tracking | |
| Crons | | |
| AI Monitoring | OpenAI/Anthropic/LangChain/etc. detected | |
Propose: "I recommend Error Monitoring + Tracing + Logging. Want Profiling, Crons, or AI Monitoring too?"
根据检测结果给出具体的方案。不要提开放式问题——直接给出建议:
始终推荐(核心能力覆盖):
- ✅ 错误监控——捕获HTTP、GraphQL、RPC和WebSocket上下文中的未处理异常
- ✅ 链路追踪——自动为中间件、守卫、管道、拦截器、过滤器和路由处理函数埋点
检测到对应场景时推荐:
- ✅ 性能分析——对CPU性能有要求的生产应用()
@sentry/profiling-node - ✅ 日志记录——结构化Sentry日志+可选的控制台输出捕获
- ✅ 定时任务监控——检测到、Bull或BullMQ时
@nestjs/schedule - ✅ 指标监控——业务KPI或SLO追踪场景
- ✅ AI监控——检测到OpenAI/Anthropic/LangChain等时(自动埋点,无需配置)
推荐矩阵:
| 功能 | 推荐场景 | 参考文档 |
|---|---|---|
| 错误监控 | 始终推荐——必备基础能力 | |
| 链路追踪 | 始终推荐——NestJS生命周期自动埋点 | |
| 性能分析 | 生产环境+CPU敏感型工作负载 | |
| 日志记录 | 始终推荐;增强结构化日志聚合能力 | |
| 指标监控 | 自定义业务KPI或SLO追踪 | |
| 定时任务监控 | 检测到 | |
| AI监控 | 检测到OpenAI/Anthropic/LangChain等时 | |
推荐话术:“我建议配置错误监控+链路追踪+日志记录。是否还需要性能分析、定时任务监控或AI监控?”
Phase 3: Guide
阶段3:配置引导
Install
安装
bash
undefinedbash
undefinedCore SDK (always required — includes @sentry/node)
Core SDK (always required — includes @sentry/node)
npm install @sentry/nestjs
npm install @sentry/nestjs
With profiling support (optional)
With profiling support (optional)
npm install @sentry/nestjs @sentry/profiling-node
> ⚠️ **Do NOT install `@sentry/node` alongside `@sentry/nestjs`** — `@sentry/nestjs` re-exports everything from `@sentry/node`. Installing both causes duplicate registration.npm install @sentry/nestjs @sentry/profiling-node
> ⚠️ **不要同时安装`@sentry/node`和`@sentry/nestjs`**——`@sentry/nestjs`已经重导出了`@sentry/node`的所有内容。同时安装会导致重复注册。Three-File Setup (Required)
三文件配置(必填)
NestJS requires a specific three-file initialization pattern because the Sentry SDK must patch Node.js modules (via OpenTelemetry) before NestJS loads them.
Before creating new files, check Phase 1 results:
- If
already exists → modify it, don't create a new one.instrument.ts- If a config class drives
→ read options from the config instead of hardcoding env vars.Sentry.init()- If a Sentry DI wrapper exists → use it for runtime calls instead of importing
directly in services/controllers.@sentry/nestjs
NestJS需要特定的三文件初始化模式,因为Sentry SDK必须在NestJS加载模块前(通过OpenTelemetry)对Node.js模块进行补丁。
创建新文件前,查看阶段1的检测结果:
- 如果
已存在→修改它,不要新建。instrument.ts- 如果存在配置类驱动
→从配置读取选项,不要硬编码环境变量。Sentry.init()- 如果存在Sentry DI封装→运行时调用使用封装实例,不要在服务/控制器中直接导入
。@sentry/nestjs
Step 1: Create src/instrument.ts
src/instrument.ts步骤1:创建src/instrument.ts
src/instrument.tstypescript
import * as Sentry from "@sentry/nestjs";
// Optional: add profiling
// import { nodeProfilingIntegration } from "@sentry/profiling-node";
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.SENTRY_ENVIRONMENT ?? "production",
release: process.env.SENTRY_RELEASE,
sendDefaultPii: true,
// Tracing — lower to 0.1–0.2 in high-traffic production
tracesSampleRate: 1.0,
// Profiling (requires @sentry/profiling-node)
// integrations: [nodeProfilingIntegration()],
// profileSessionSampleRate: 1.0,
// profileLifecycle: "trace",
// Structured logs (SDK ≥ 9.41.0)
enableLogs: true,
});Config-driven : If Phase 1 found a typed config class (e.g. ), read options from it instead of using raw . This is common in NestJS apps that use or custom config loaders:
Sentry.init()SentryConfigprocess.env@nestjs/configtypescript
import * as Sentry from "@sentry/nestjs";
import { loadConfiguration } from "./config";
const config = loadConfiguration();
Sentry.init({
dsn: config.sentry.dsn,
environment: config.sentry.environment ?? "production",
release: config.sentry.release,
sendDefaultPii: config.sentry.sendDefaultPii ?? true,
tracesSampleRate: config.sentry.tracesSampleRate ?? 1.0,
profileSessionSampleRate: config.sentry.profilesSampleRate ?? 1.0,
profileLifecycle: "trace",
enableLogs: true,
});When adding new SDK options (e.g. , ), add them to the config type so they can be configured per environment.
sendDefaultPiiprofileSessionSampleRatetypescript
import * as Sentry from "@sentry/nestjs";
// Optional: add profiling
// import { nodeProfilingIntegration } from "@sentry/profiling-node";
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.SENTRY_ENVIRONMENT ?? "production",
release: process.env.SENTRY_RELEASE,
sendDefaultPii: true,
// Tracing — lower to 0.1–0.2 in high-traffic production
tracesSampleRate: 1.0,
// Profiling (requires @sentry/profiling-node)
// integrations: [nodeProfilingIntegration()],
// profileSessionSampleRate: 1.0,
// profileLifecycle: "trace",
// Structured logs (SDK ≥ 9.41.0)
enableLogs: true,
});配置驱动的: 如果阶段1检测到类型化配置类(例如),从配置读取选项而不是直接使用。这种模式在使用或自定义配置加载器的NestJS应用中很常见:
Sentry.init()SentryConfigprocess.env@nestjs/configtypescript
import * as Sentry from "@sentry/nestjs";
import { loadConfiguration } from "./config";
const config = loadConfiguration();
Sentry.init({
dsn: config.sentry.dsn,
environment: config.sentry.environment ?? "production",
release: config.sentry.release,
sendDefaultPii: config.sentry.sendDefaultPii ?? true,
tracesSampleRate: config.sentry.tracesSampleRate ?? 1.0,
profileSessionSampleRate: config.sentry.profilesSampleRate ?? 1.0,
profileLifecycle: "trace",
enableLogs: true,
});添加新的SDK选项时(例如、),将其添加到配置类型中,以便可以按环境配置。
sendDefaultPiiprofileSessionSampleRateStep 2: Import instrument.ts
FIRST in src/main.ts
instrument.tssrc/main.ts步骤2:在src/main.ts
中第一个导入instrument.ts
src/main.tsinstrument.tstypescript
// instrument.ts MUST be the very first import — before NestJS or any other module
import "./instrument";
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Enable graceful shutdown — flushes Sentry events on SIGTERM/SIGINT
app.enableShutdownHooks();
await app.listen(3000);
}
bootstrap();Why first? OpenTelemetry must monkey-patch,http, database drivers, and other modules before they load. Any module that loads beforeexpresswill not be auto-instrumented.instrument.ts
typescript
// instrument.ts MUST be the very first import — before NestJS or any other module
import "./instrument";
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Enable graceful shutdown — flushes Sentry events on SIGTERM/SIGINT
app.enableShutdownHooks();
await app.listen(3000);
}
bootstrap();为什么要放在第一个? OpenTelemetry必须在、http、数据库驱动等模块加载前对其进行猴子补丁。任何在express之前加载的模块都不会被自动埋点。instrument.ts
Step 3: Register SentryModule
and SentryGlobalFilter
in src/app.module.ts
SentryModuleSentryGlobalFiltersrc/app.module.ts步骤3:在src/app.module.ts
中注册SentryModule
和SentryGlobalFilter
src/app.module.tsSentryModuleSentryGlobalFiltertypescript
import { Module } from "@nestjs/common";
import { APP_FILTER } from "@nestjs/core";
import { SentryModule, SentryGlobalFilter } from "@sentry/nestjs/setup";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
@Module({
imports: [
SentryModule.forRoot(), // Registers SentryTracingInterceptor globally
],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_FILTER,
useClass: SentryGlobalFilter, // Captures all unhandled exceptions
},
],
})
export class AppModule {}What each piece does:
- — registers
SentryModule.forRoot()as a globalSentryTracingInterceptor, enabling HTTP transaction namingAPP_INTERCEPTOR - — extends
SentryGlobalFilter; captures exceptions across HTTP, GraphQL (rethrowsBaseExceptionFilterwithout reporting), and RPC contextsHttpException
⚠️ Do NOT registertwice. If Phase 1 found it already imported in a shared library module (e.g. aSentryModule.forRoot()orSentryProxyModule), do not add it again inAnalyticsModule. Duplicate registration causes every span to be intercepted twice, bloating trace data.AppModule
⚠️ Two entrypoints, different imports:
→ SDK init, capture APIs, decorators (@sentry/nestjs,SentryTraced,SentryCron)SentryExceptionCaptured → NestJS DI constructs (@sentry/nestjs/setup,SentryModule)SentryGlobalFilterNever importfromSentryModule(main entrypoint) — it loads@sentry/nestjsbefore OpenTelemetry patches it, breaking auto-instrumentation.@nestjs/common
typescript
import { Module } from "@nestjs/common";
import { APP_FILTER } from "@nestjs/core";
import { SentryModule, SentryGlobalFilter } from "@sentry/nestjs/setup";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
@Module({
imports: [
SentryModule.forRoot(), // Registers SentryTracingInterceptor globally
],
controllers: [AppController],
providers: [
AppService,
{
provide: APP_FILTER,
useClass: SentryGlobalFilter, // Captures all unhandled exceptions
},
],
})
export class AppModule {}各部分作用:
- ——将
SentryModule.forRoot()注册为全局SentryTracingInterceptor,启用HTTP事务命名APP_INTERCEPTOR - ——继承
SentryGlobalFilter;捕获HTTP、GraphQL(重新抛出BaseExceptionFilter不上报)和RPC上下文中的所有未处理异常HttpException
⚠️ 不要重复注册。 如果阶段1检测到它已经在共享库模块(例如SentryModule.forRoot()或SentryProxyModule)中导入,不要在AnalyticsModule中再次添加。重复注册会导致每个span被拦截两次,导致 trace 数据冗余。AppModule
⚠️ 两个入口点,不同导入方式:
→ SDK初始化、捕获API、装饰器(@sentry/nestjs、SentryTraced、SentryCron)SentryExceptionCaptured → NestJS DI 构造(@sentry/nestjs/setup、SentryModule)SentryGlobalFilter永远不要从(主入口)导入@sentry/nestjs——它会在OpenTelemetry补丁前加载SentryModule,导致自动埋点失效。@nestjs/common
ESM Setup (Node ≥ 18.19.0)
ESM配置(Node ≥ 18.19.0)
For ESM applications, use instead of a file import:
--importjavascript
// instrument.mjs
import * as Sentry from "@sentry/nestjs";
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 1.0,
});json
// package.json
{
"scripts": {
"start": "node --import ./instrument.mjs -r ts-node/register src/main.ts"
}
}Or via environment:
bash
NODE_OPTIONS="--import ./instrument.mjs" npm run start对于ESM应用,使用参数而不是文件导入:
--importjavascript
// instrument.mjs
import * as Sentry from "@sentry/nestjs";
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 1.0,
});json
// package.json
{
"scripts": {
"start": "node --import ./instrument.mjs -r ts-node/register src/main.ts"
}
}或者通过环境变量配置:
bash
NODE_OPTIONS="--import ./instrument.mjs" npm run startException Filter Options
异常过滤器选项
Choose the approach that fits your existing architecture:
选择符合现有架构的方案:
Option A: No existing global filter — use SentryGlobalFilter
(recommended)
SentryGlobalFilter选项A:无现有全局过滤器——使用SentryGlobalFilter
(推荐)
SentryGlobalFilterAlready covered in Step 3 above. This is the simplest option.
已在上方步骤3中涵盖。这是最简单的方案。
Option B: Existing custom global filter — add @SentryExceptionCaptured()
decorator
@SentryExceptionCaptured()选项B:已有自定义全局过滤器——添加@SentryExceptionCaptured()
装饰器
@SentryExceptionCaptured()typescript
import { Catch, ExceptionFilter, ArgumentsHost } from "@nestjs/common";
import { SentryExceptionCaptured } from "@sentry/nestjs";
@Catch()
export class YourExistingFilter implements ExceptionFilter {
@SentryExceptionCaptured() // Wraps catch() to auto-report exceptions
catch(exception: unknown, host: ArgumentsHost): void {
// Your existing error handling continues unchanged
}
}typescript
import { Catch, ExceptionFilter, ArgumentsHost } from "@nestjs/common";
import { SentryExceptionCaptured } from "@sentry/nestjs";
@Catch()
export class YourExistingFilter implements ExceptionFilter {
@SentryExceptionCaptured() // Wraps catch() to auto-report exceptions
catch(exception: unknown, host: ArgumentsHost): void {
// Your existing error handling continues unchanged
}
}Option C: Specific exception type — manual capture
选项C:特定异常类型——手动捕获
typescript
import { ArgumentsHost, Catch } from "@nestjs/common";
import { BaseExceptionFilter } from "@nestjs/core";
import * as Sentry from "@sentry/nestjs";
@Catch(ExampleException)
export class ExampleExceptionFilter extends BaseExceptionFilter {
catch(exception: ExampleException, host: ArgumentsHost) {
Sentry.captureException(exception);
super.catch(exception, host);
}
}typescript
import { ArgumentsHost, Catch } from "@nestjs/common";
import { BaseExceptionFilter } from "@nestjs/core";
import * as Sentry from "@sentry/nestjs";
@Catch(ExampleException)
export class ExampleExceptionFilter extends BaseExceptionFilter {
catch(exception: ExampleException, host: ArgumentsHost) {
Sentry.captureException(exception);
super.catch(exception, host);
}
}Option D: Microservice RPC exceptions
选项D:微服务RPC异常
typescript
import { Catch, RpcExceptionFilter, ArgumentsHost } from "@nestjs/common";
import { Observable, throwError } from "rxjs";
import { RpcException } from "@nestjs/microservices";
import * as Sentry from "@sentry/nestjs";
@Catch(RpcException)
export class SentryRpcFilter implements RpcExceptionFilter<RpcException> {
catch(exception: RpcException, host: ArgumentsHost): Observable<any> {
Sentry.captureException(exception);
return throwError(() => exception.getError());
}
}typescript
import { Catch, RpcExceptionFilter, ArgumentsHost } from "@nestjs/common";
import { Observable, throwError } from "rxjs";
import { RpcException } from "@nestjs/microservices";
import * as Sentry from "@sentry/nestjs";
@Catch(RpcException)
export class SentryRpcFilter implements RpcExceptionFilter<RpcException> {
catch(exception: RpcException, host: ArgumentsHost): Observable<any> {
Sentry.captureException(exception);
return throwError(() => exception.getError());
}
}Decorators
装饰器
@SentryTraced(op?)
— Instrument any method
@SentryTraced(op?)@SentryTraced(op?)
——为任意方法埋点
@SentryTraced(op?)typescript
import { Injectable } from "@nestjs/common";
import { SentryTraced } from "@sentry/nestjs";
@Injectable()
export class OrderService {
@SentryTraced("order.process")
async processOrder(orderId: string): Promise<void> {
// Automatically wrapped in a Sentry span
}
@SentryTraced() // Defaults to op: "function"
async fetchInventory() { ... }
}typescript
import { Injectable } from "@nestjs/common";
import { SentryTraced } from "@sentry/nestjs";
@Injectable()
export class OrderService {
@SentryTraced("order.process")
async processOrder(orderId: string): Promise<void> {
// Automatically wrapped in a Sentry span
}
@SentryTraced() // Defaults to op: "function"
async fetchInventory() { ... }
}@SentryCron(slug, config?)
— Monitor scheduled jobs
@SentryCron(slug, config?)@SentryCron(slug, config?)
——监控定时任务
@SentryCron(slug, config?)typescript
import { Injectable } from "@nestjs/common";
import { Cron } from "@nestjs/schedule";
import { SentryCron } from "@sentry/nestjs";
@Injectable()
export class ReportService {
@Cron("0 * * * *")
@SentryCron("hourly-report", {
// @SentryCron must come AFTER @Cron
schedule: { type: "crontab", value: "0 * * * *" },
checkinMargin: 2, // Minutes before marking missed
maxRuntime: 10, // Max runtime in minutes
timezone: "UTC",
})
async generateReport() {
// Check-in sent automatically on start/success/failure
}
}typescript
import { Injectable } from "@nestjs/common";
import { Cron } from "@nestjs/schedule";
import { SentryCron } from "@sentry/nestjs";
@Injectable()
export class ReportService {
@Cron("0 * * * *")
@SentryCron("hourly-report", {
// @SentryCron must come AFTER @Cron
schedule: { type: "crontab", value: "0 * * * *" },
checkinMargin: 2, // Minutes before marking missed
maxRuntime: 10, // Max runtime in minutes
timezone: "UTC",
})
async generateReport() {
// Check-in sent automatically on start/success/failure
}
}Background Job Scope Isolation
后台任务作用域隔离
Background jobs share the default isolation scope — wrap with to prevent cross-contamination:
Sentry.withIsolationScope()typescript
import * as Sentry from "@sentry/nestjs";
import { Injectable } from "@nestjs/common";
import { Cron, CronExpression } from "@nestjs/schedule";
@Injectable()
export class JobService {
@Cron(CronExpression.EVERY_HOUR)
handleCron() {
Sentry.withIsolationScope(() => {
Sentry.setTag("job", "hourly-sync");
this.doWork();
});
}
}Apply to: , , , , and any code outside the request lifecycle.
withIsolationScope@Cron()@Interval()@OnEvent()@Processor()后台任务共享默认隔离作用域——使用包裹以防止数据污染:
Sentry.withIsolationScope()typescript
import * as Sentry from "@sentry/nestjs";
import { Injectable } from "@nestjs/common";
import { Cron, CronExpression } from "@nestjs/schedule";
@Injectable()
export class JobService {
@Cron(CronExpression.EVERY_HOUR)
handleCron() {
Sentry.withIsolationScope(() => {
Sentry.setTag("job", "hourly-sync");
this.doWork();
});
}
}将应用于:、、、以及所有请求生命周期外的代码。
withIsolationScope@Cron()@Interval()@OnEvent()@Processor()Working with Sentry DI Wrappers
使用Sentry DI封装
Some NestJS projects wrap Sentry behind a dependency injection token (e.g. ) for testability and decoupling. If Phase 1 detected this pattern, use the injected service for all runtime Sentry calls — do not import directly in controllers, services, or processors.
SENTRY_PROXY_TOKEN@sentry/nestjstypescript
import { Controller, Inject } from "@nestjs/common";
import { SENTRY_PROXY_TOKEN, type SentryProxyService } from "./sentry-proxy";
@Controller("orders")
export class OrderController {
constructor(
@Inject(SENTRY_PROXY_TOKEN) private readonly sentry: SentryProxyService,
private readonly orderService: OrderService,
) {}
@Post()
async createOrder(@Body() dto: CreateOrderDto) {
return this.sentry.startSpan(
{ name: "createOrder", op: "http" },
async () => this.orderService.create(dto),
);
}
}Where direct import is still correct:
@sentry/nestjs- — always uses
instrument.tsforimport * as Sentry from "@sentry/nestjs"Sentry.init() - Standalone scripts and exception filters that run outside the DI container
部分NestJS项目会将Sentry封装在依赖注入token后(例如)以提升可测试性和解耦。如果阶段1检测到这种模式,所有运行时Sentry调用都使用注入的服务——不要在控制器、服务或处理器中直接导入。
SENTRY_PROXY_TOKEN@sentry/nestjstypescript
import { Controller, Inject } from "@nestjs/common";
import { SENTRY_PROXY_TOKEN, type SentryProxyService } from "./sentry-proxy";
@Controller("orders")
export class OrderController {
constructor(
@Inject(SENTRY_PROXY_TOKEN) private readonly sentry: SentryProxyService,
private readonly orderService: OrderService,
) {}
@Post()
async createOrder(@Body() dto: CreateOrderDto) {
return this.sentry.startSpan(
{ name: "createOrder", op: "http" },
async () => this.orderService.create(dto),
);
}
}仍然可以直接导入的场景:
@sentry/nestjs- ——始终使用
instrument.ts进行import * as Sentry from "@sentry/nestjs"Sentry.init() - 独立脚本和运行在DI容器外的异常过滤器
Verification
验证
Add a test endpoint to confirm events reach Sentry:
typescript
import { Controller, Get } from "@nestjs/common";
import * as Sentry from "@sentry/nestjs";
@Controller()
export class DebugController {
@Get("/debug-sentry")
triggerError() {
throw new Error("My first Sentry error from NestJS!");
}
@Get("/debug-sentry-span")
triggerSpan() {
return Sentry.startSpan({ op: "test", name: "NestJS Test Span" }, () => {
return { status: "span created" };
});
}
}Hit and check the Sentry Issues dashboard within seconds.
GET /debug-sentry添加测试端点确认事件能到达Sentry:
typescript
import { Controller, Get } from "@nestjs/common";
import * as Sentry from "@sentry/nestjs";
@Controller()
export class DebugController {
@Get("/debug-sentry")
triggerError() {
throw new Error("My first Sentry error from NestJS!");
}
@Get("/debug-sentry-span")
triggerSpan() {
return Sentry.startSpan({ op: "test", name: "NestJS Test Span" }, () => {
return { status: "span created" };
});
}
}访问,几秒内即可在Sentry问题面板中看到事件。
GET /debug-sentryFor Each Agreed Feature
每个已确认的功能
Walk through features one at a time. Load the reference, follow its steps, verify before moving on:
| Feature | Reference file | Load when... |
|---|---|---|
| Error Monitoring | | Always (baseline) |
| Tracing | | Always (NestJS routes are auto-traced) |
| Profiling | | CPU-intensive production apps |
| Logging | | Structured log aggregation needed |
| Metrics | | Custom KPIs / SLO tracking |
| Crons | | Scheduled jobs or task queues |
| AI Monitoring | | OpenAI/Anthropic/LangChain detected |
For each feature: , follow steps exactly, verify it works.
Read ${SKILL_ROOT}/references/<feature>.md逐个配置功能。加载参考文档,遵循步骤,验证通过后再进行下一步:
| 功能 | 参考文件 | 加载时机 |
|---|---|---|
| 错误监控 | | 始终(基础能力) |
| 链路追踪 | | 始终(NestJS路由自动追踪) |
| 性能分析 | | CPU密集型生产应用 |
| 日志记录 | | 需要结构化日志聚合 |
| 指标监控 | | 自定义KPI / SLO追踪 |
| 定时任务监控 | | 定时任务或任务队列场景 |
| AI监控 | | 检测到OpenAI/Anthropic/LangChain时 |
每个功能的配置流程:,严格遵循步骤,验证功能正常。
阅读${SKILL_ROOT}/references/<feature>.mdConfiguration Reference
配置参考
Key Sentry.init()
Options
Sentry.init()核心Sentry.init()
选项
Sentry.init()| Option | Type | Default | Purpose |
|---|---|---|---|
| | — | SDK disabled if empty; env: |
| | | e.g., |
| | — | e.g., |
| | | Include IP addresses and request headers |
| | — | Transaction sample rate; |
| | — | Custom per-transaction sampling (overrides rate) |
| | — | URLs to propagate |
| | — | Continuous profiling session rate (SDK ≥ 10.27.0) |
| | | |
| | | Send structured logs to Sentry (SDK ≥ 9.41.0) |
| | | Error message patterns to suppress |
| | | Transaction name patterns to suppress |
| | — | Hook to mutate or drop error events |
| | — | Hook to mutate or drop transaction events |
| | — | Hook to mutate or drop log events |
| | | Verbose SDK debug output |
| | | Max breadcrumbs per event |
| 选项 | 类型 | 默认值 | 用途 |
|---|---|---|---|
| | — | 为空时SDK禁用;环境变量: |
| | | 例如 |
| | — | 例如 |
| | | 是否包含IP地址和请求头 |
| | — | 事务采样率; |
| | — | 自定义按事务采样(覆盖采样率) |
| `Array<string\ | RegExp>` | — |
| | — | 持续性能分析会话采样率(SDK ≥ 10.27.0) |
| `"trace"\ | "manual"` | |
| | | 发送结构化日志到Sentry(SDK ≥ 9.41.0) |
| `Array<string\ | RegExp>` | |
| `Array<string\ | RegExp>` | |
| | — | 修改或丢弃错误事件的钩子 |
| | — | 修改或丢弃事务事件的钩子 |
| | — | 修改或丢弃日志事件的钩子 |
| | | 输出SDK详细调试日志 |
| | | 每个事件的最大面包屑数量 |
Environment Variables
环境变量
| Variable | Maps to | Notes |
|---|---|---|
| | Used if |
| | Also auto-detected from git SHA, Heroku, CircleCI |
| | Falls back to |
| CLI/source maps | For |
| CLI/source maps | Organization slug |
| CLI/source maps | Project slug |
| 变量名 | 对应配置项 | 说明 |
|---|---|---|
| | 未向 |
| | 也会自动从git SHA、Heroku、CircleCI检测 |
| | 兜底值为 |
| CLI/源码映射 | 用于 |
| CLI/源码映射 | 组织slug |
| CLI/源码映射 | 项目slug |
Auto-Enabled Integrations
自动启用的集成
These integrations activate automatically when their packages are detected — no needed:
integrations: [...]| Auto-enabled | Notes |
|---|---|
| Outgoing HTTP calls via |
| Express adapter (default NestJS) |
| NestJS lifecycle (middleware, guards, pipes, interceptors, handlers) |
| Uncaught exceptions |
| Unhandled promise rejections |
| OpenAI SDK (when installed) |
| Anthropic SDK (when installed) |
| LangChain (when installed) |
| GraphQL (when |
| |
| |
| MongoDB / Mongoose |
| |
检测到对应包时这些集成会自动激活——无需手动配置:
integrations: [...]| 自动集成名 | 说明 |
|---|---|
| 通过 |
| Express适配器(NestJS默认) |
| NestJS生命周期(中间件、守卫、管道、拦截器、处理函数) |
| 未捕获异常 |
| 未处理Promise拒绝 |
| OpenAI SDK(安装时自动激活) |
| Anthropic SDK(安装时自动激活) |
| LangChain(安装时自动激活) |
| GraphQL(存在 |
| |
| |
| MongoDB / Mongoose |
| |
Integrations Requiring Manual Setup
需要手动设置的集成
| Integration | When to add | Code |
|---|---|---|
| Profiling desired | |
| Prisma ORM used | |
| Capture console output | |
| Capture local var values in errors | |
| 集成名 | 添加场景 | 代码 |
|---|---|---|
| 需要性能分析 | |
| 使用Prisma ORM | |
| 捕获控制台输出 | |
| 捕获错误中的局部变量值 | |
Verification
验证
Test that Sentry is receiving events:
typescript
// Add a test endpoint (remove before production)
@Get("/debug-sentry")
getError() {
throw new Error("My first Sentry error!");
}Or send a test message without crashing:
typescript
import * as Sentry from "@sentry/nestjs";
Sentry.captureMessage("NestJS Sentry SDK test");If nothing appears:
- Set in
debug: true— prints SDK internals to stdoutSentry.init() - Verify env var is set in the running process
SENTRY_DSN - Check that is the first line in
import "./instrument"main.ts - Confirm is imported in
SentryModule.forRoot()AppModule - Check DSN format:
https://<key>@o<org>.ingest.sentry.io/<project>
测试Sentry是否能收到事件:
typescript
// Add a test endpoint (remove before production)
@Get("/debug-sentry")
getError() {
throw new Error("My first Sentry error!");
}或者不崩溃的情况下发送测试消息:
typescript
import * as Sentry from "@sentry/nestjs";
Sentry.captureMessage("NestJS Sentry SDK test");如果没有收到事件:
- 在中设置
Sentry.init()——在标准输出打印SDK内部日志debug: true - 验证运行进程中环境变量已设置
SENTRY_DSN - 检查是
import "./instrument"中的第一行导入main.ts - 确认已在
SentryModule.forRoot()中导入AppModule - 检查DSN格式:
https://<key>@o<org>.ingest.sentry.io/<project>
Phase 4: Cross-Link
阶段4:交叉推荐
After completing NestJS setup, check for a companion frontend missing Sentry:
bash
ls -d ../frontend ../web ../client ../ui 2>/dev/null
cat ../frontend/package.json ../web/package.json 2>/dev/null \
| grep -E '"react"|"svelte"|"vue"|"next"|"nuxt"'If a frontend exists without Sentry, suggest the matching skill:
| Frontend detected | Suggest skill |
|---|---|
| Next.js | |
| React | |
| Svelte / SvelteKit | |
| Vue / Nuxt | Use |
| React Native / Expo | |
完成NestJS配置后,检查是否存在未配置Sentry的配套前端:
bash
ls -d ../frontend ../web ../client ../ui 2>/dev/null
cat ../frontend/package.json ../web/package.json 2>/dev/null \\
| grep -E '"react"|"svelte"|"vue"|"next"|"nuxt"'如果存在未配置Sentry的前端,推荐对应的技能:
| 检测到的前端 | 推荐技能 |
|---|---|
| Next.js | |
| React | |
| Svelte / SvelteKit | |
| Vue / Nuxt | 使用 |
| React Native / Expo | |
Troubleshooting
问题排查
| Issue | Solution |
|---|---|
| Events not appearing | Set |
| Malformed DSN error | Format: |
| Exceptions not captured | Ensure |
| Auto-instrumentation not working | |
| Profiling not starting | Requires |
| Requires SDK ≥ 9.41.0 |
| No traces appearing | Verify |
| Too many transactions | Lower |
| Fastify + GraphQL issues | Known edge cases — see GitHub #13388; prefer Express for GraphQL |
| Background job events mixed | Wrap job body in |
| Prisma spans missing | Add |
| ESM syntax errors | Set |
| Must import from |
| RPC exceptions not captured | Add dedicated |
| WebSocket exceptions not captured | Use |
| Decorator order matters — |
| TypeScript path alias issues | Ensure |
| Many projects ban namespace imports. Use named imports ( |
| |
| Duplicate spans on every request | |
Config property not recognized in | When using a typed config class, new SDK options must be added to the config type definition and the project rebuilt before TypeScript recognizes them |
| 问题 | 解决方案 |
|---|---|
| 没有收到事件 | 设置 |
| DSN格式错误 | 格式要求: |
| 异常未捕获 | 确保 |
| 自动埋点不生效 | |
| 性能分析未启动 | 需要 |
| 需要SDK ≥ 9.41.0 |
| 没有trace数据 | 验证 |
| 事务数量过多 | 降低 |
| Fastify + GraphQL问题 | 已知边缘问题——参见GitHub #13388;GraphQL场景优先使用Express |
| 后台任务事件混杂 | 使用 |
| Prisma span缺失 | 在 |
| ESM语法错误 | 设置 |
| 必须从 |
| RPC异常未捕获 | 添加专用 |
| WebSocket异常未捕获 | 在网关 |
| 装饰器顺序很重要—— |
| TypeScript路径别名问题 | 确保 |
| 很多项目禁止命名空间导入。使用命名导入( |
| |
| 每个请求都有重复span | |
| 使用类型化配置类时,新的SDK选项必须添加到配置类型定义中,项目重建后TypeScript才能识别它们 |
Version Requirements
版本要求
| Feature | Minimum SDK Version |
|---|---|
| 8.0.0 |
| 8.15.0 |
| 8.16.0 |
| Event Emitter auto-instrumentation | 8.39.0 |
| 8.40.0 |
| 9.41.0 |
| 10.27.0 |
| Node.js requirement | ≥ 18 |
Node.js for ESM | ≥ 18.19.0 |
| NestJS compatibility | 8.x – 11.x |
| 功能 | 最低SDK版本 |
|---|---|
| 8.0.0 |
| 8.15.0 |
| 8.16.0 |
| Event Emitter自动埋点 | 8.39.0 |
| 8.40.0 |
| 9.41.0 |
| 10.27.0 |
| Node.js版本要求 | ≥ 18 |
ESM | ≥ 18.19.0 |
| NestJS兼容性 | 8.x – 11.x |
| ", |