@danieljvdm/dev-kit 1.0.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/package.json +1 -1
- package/skill-sources.jsonc +2 -33
- package/skill-sources.lock.json +15 -117
- package/skills/animate/LICENSE +21 -0
- package/skills/animate/NOTICE +10 -0
- package/skills/animate/SKILL.md +34 -0
- package/skills/animate/references/gestures.md +27 -0
- package/skills/animate/references/glossary.md +136 -0
- package/skills/animate/references/implementation.md +22 -0
- package/skills/animate/references/opportunities.md +18 -0
- package/skills/animate/references/principles.md +48 -0
- package/skills/animate/references/review.md +19 -0
- package/skills/cloudflare-workers/LICENSE +202 -0
- package/skills/cloudflare-workers/NOTICE +9 -0
- package/skills/cloudflare-workers/SKILL.md +26 -0
- package/skills/cloudflare-workers/references/durable-objects.md +68 -0
- package/skills/cloudflare-workers/references/sandbox.md +48 -0
- package/skills/cloudflare-workers/references/workers.md +63 -0
- package/skills/cloudflare-workers/references/wrangler.md +56 -0
- package/skills/design-ui/LICENSE +21 -0
- package/skills/design-ui/NOTICE +8 -0
- package/skills/design-ui/SKILL.md +29 -0
- package/skills/design-ui/references/appearance.md +22 -0
- package/skills/design-ui/references/components.md +33 -0
- package/skills/design-ui/references/exploration.md +50 -0
- package/skills/design-ui/references/libraries.md +39 -0
- package/skills/design-ui/references/themes.md +23 -0
- package/skills/dev-kit/SKILL.md +19 -38
- package/skills/dev-kit/references/cloudflare-worker-api.md +1 -1
- package/skills/dev-kit/references/skills.md +2 -2
- package/skills/effect-development/SKILL.md +27 -0
- package/skills/effect-development/agents/openai.yaml +4 -0
- package/skills/effect-development/references/api/index.md +32 -0
- package/skills/effect-development/references/api/schema-codecs.md +15 -0
- package/skills/{build-effect-apis/references → effect-development/references/api}/verification.md +10 -5
- package/skills/{effect-architecture-audit/SKILL.md → effect-development/references/architecture/index.md} +1 -6
- package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-client.md +8 -6
- package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-testing.md +7 -2
- package/skills/effect-development/references/atom/index.md +40 -0
- package/skills/{build-effect-clis/references → effect-development/references/cli}/entrypoints-and-testing.md +6 -2
- package/skills/effect-development/references/cli/index.md +39 -0
- package/skills/effect-development/references/setup.md +15 -0
- package/skills/open-pull-request/SKILL.md +10 -70
- package/skills/open-pull-request/references/evidence.md +22 -0
- package/skills/open-pull-request/references/explanation.md +21 -0
- package/skills/open-pull-request/references/publication.md +21 -0
- package/skills/sentry/LICENSE +202 -0
- package/skills/sentry/LICENSE-UPSTREAM +21 -0
- package/skills/sentry/NOTICE +14 -0
- package/skills/sentry/SKILL.md +33 -0
- package/skills/sentry/references/alert-payloads.md +105 -0
- package/skills/sentry/references/alerts.md +17 -0
- package/skills/sentry/references/artifacts.md +25 -0
- package/skills/sentry/references/auth-token.md +65 -0
- package/skills/sentry/references/concepts/ai-monitoring.md +131 -0
- package/skills/sentry/references/concepts/choosing-a-signal.md +78 -0
- package/skills/sentry/references/concepts/crons.md +50 -0
- package/skills/sentry/references/concepts/data-scrubbing.md +43 -0
- package/skills/sentry/references/concepts/errors.md +40 -0
- package/skills/sentry/references/concepts/logging.md +85 -0
- package/skills/sentry/references/concepts/metrics.md +49 -0
- package/skills/sentry/references/concepts/monitors.md +78 -0
- package/skills/sentry/references/concepts/profiling.md +38 -0
- package/skills/sentry/references/concepts/reduce-volume.md +49 -0
- package/skills/sentry/references/concepts/releases.md +43 -0
- package/skills/sentry/references/concepts/session-replay.md +35 -0
- package/skills/sentry/references/concepts/tracing.md +54 -0
- package/skills/sentry/references/concepts/user-feedback.md +36 -0
- package/skills/sentry/references/debug-artifacts/android.md +68 -0
- package/skills/sentry/references/debug-artifacts/apple.md +96 -0
- package/skills/sentry/references/debug-artifacts/dotnet.md +70 -0
- package/skills/sentry/references/debug-artifacts/flutter.md +65 -0
- package/skills/sentry/references/debug-artifacts/index.md +75 -0
- package/skills/sentry/references/debug-artifacts/javascript.md +94 -0
- package/skills/sentry/references/debug-artifacts/matching.md +73 -0
- package/skills/sentry/references/debug-artifacts/react-native.md +75 -0
- package/skills/sentry/references/first-error-setup.md +25 -0
- package/skills/sentry/references/instrumentation.md +30 -0
- package/skills/sentry/references/issues.md +32 -0
- package/skills/sentry/references/new-project.md +17 -0
- package/skills/sentry/references/otel-exporter.md +30 -0
- package/skills/sentry/references/release-workflow.md +31 -0
- package/skills/sentry/references/releases/ci-pipeline.md +214 -0
- package/skills/sentry/references/releases/index.md +93 -0
- package/skills/sentry/references/releases/suspect-commits.md +155 -0
- package/skills/sentry/references/releases/tagging.md +131 -0
- package/skills/sentry/references/releases/troubleshooting.md +67 -0
- package/skills/sentry/references/sdks/android/crons.md +305 -0
- package/skills/sentry/references/sdks/android/error-monitoring.md +800 -0
- package/skills/sentry/references/sdks/android/index.md +748 -0
- package/skills/sentry/references/sdks/android/integrations.md +48 -0
- package/skills/sentry/references/sdks/android/logging.md +374 -0
- package/skills/sentry/references/sdks/android/metrics.md +288 -0
- package/skills/sentry/references/sdks/android/profiling.md +397 -0
- package/skills/sentry/references/sdks/android/session-replay.md +406 -0
- package/skills/sentry/references/sdks/android/tracing.md +861 -0
- package/skills/sentry/references/sdks/browser/error-monitoring.md +861 -0
- package/skills/sentry/references/sdks/browser/index.md +714 -0
- package/skills/sentry/references/sdks/browser/logging.md +315 -0
- package/skills/sentry/references/sdks/browser/profiling.md +236 -0
- package/skills/sentry/references/sdks/browser/session-replay.md +586 -0
- package/skills/sentry/references/sdks/browser/tracing.md +561 -0
- package/skills/sentry/references/sdks/browser/user-feedback.md +354 -0
- package/skills/sentry/references/sdks/cloudflare/ai-monitoring.md +661 -0
- package/skills/sentry/references/sdks/cloudflare/crons.md +231 -0
- package/skills/sentry/references/sdks/cloudflare/durable-objects.md +381 -0
- package/skills/sentry/references/sdks/cloudflare/error-monitoring.md +329 -0
- package/skills/sentry/references/sdks/cloudflare/index.md +698 -0
- package/skills/sentry/references/sdks/cloudflare/logging.md +169 -0
- package/skills/sentry/references/sdks/cloudflare/nodejs-compat.md +134 -0
- package/skills/sentry/references/sdks/cloudflare/tracing.md +475 -0
- package/skills/sentry/references/sdks/cocoa/error-monitoring.md +394 -0
- package/skills/sentry/references/sdks/cocoa/index.md +497 -0
- package/skills/sentry/references/sdks/cocoa/logging.md +209 -0
- package/skills/sentry/references/sdks/cocoa/metrics.md +136 -0
- package/skills/sentry/references/sdks/cocoa/profiling.md +223 -0
- package/skills/sentry/references/sdks/cocoa/session-replay.md +257 -0
- package/skills/sentry/references/sdks/cocoa/tracing.md +524 -0
- package/skills/sentry/references/sdks/cocoa/user-feedback.md +310 -0
- package/skills/sentry/references/sdks/dotnet/crons.md +465 -0
- package/skills/sentry/references/sdks/dotnet/error-monitoring.md +1100 -0
- package/skills/sentry/references/sdks/dotnet/index.md +614 -0
- package/skills/sentry/references/sdks/dotnet/logging.md +556 -0
- package/skills/sentry/references/sdks/dotnet/metrics.md +229 -0
- package/skills/sentry/references/sdks/dotnet/profiling.md +296 -0
- package/skills/sentry/references/sdks/dotnet/tracing.md +897 -0
- package/skills/sentry/references/sdks/elixir/crons.md +371 -0
- package/skills/sentry/references/sdks/elixir/error-monitoring.md +335 -0
- package/skills/sentry/references/sdks/elixir/index.md +383 -0
- package/skills/sentry/references/sdks/elixir/logging.md +239 -0
- package/skills/sentry/references/sdks/elixir/tracing.md +233 -0
- package/skills/sentry/references/sdks/flutter/ecosystem-integrations.md +70 -0
- package/skills/sentry/references/sdks/flutter/error-monitoring.md +312 -0
- package/skills/sentry/references/sdks/flutter/index.md +728 -0
- package/skills/sentry/references/sdks/flutter/logging.md +387 -0
- package/skills/sentry/references/sdks/flutter/metrics.md +310 -0
- package/skills/sentry/references/sdks/flutter/profiling.md +214 -0
- package/skills/sentry/references/sdks/flutter/session-replay.md +308 -0
- package/skills/sentry/references/sdks/flutter/tracing.md +502 -0
- package/skills/sentry/references/sdks/go/crons.md +270 -0
- package/skills/sentry/references/sdks/go/error-monitoring.md +361 -0
- package/skills/sentry/references/sdks/go/index.md +324 -0
- package/skills/sentry/references/sdks/go/logging.md +354 -0
- package/skills/sentry/references/sdks/go/metrics.md +273 -0
- package/skills/sentry/references/sdks/go/profiling.md +46 -0
- package/skills/sentry/references/sdks/go/tracing.md +366 -0
- package/skills/sentry/references/sdks/index.md +41 -0
- package/skills/sentry/references/sdks/nestjs/ai-monitoring.md +410 -0
- package/skills/sentry/references/sdks/nestjs/crons.md +268 -0
- package/skills/sentry/references/sdks/nestjs/error-monitoring.md +729 -0
- package/skills/sentry/references/sdks/nestjs/index.md +699 -0
- package/skills/sentry/references/sdks/nestjs/logging.md +174 -0
- package/skills/sentry/references/sdks/nestjs/metrics.md +243 -0
- package/skills/sentry/references/sdks/nestjs/profiling.md +127 -0
- package/skills/sentry/references/sdks/nestjs/tracing.md +762 -0
- package/skills/sentry/references/sdks/nextjs/ai-monitoring.md +494 -0
- package/skills/sentry/references/sdks/nextjs/crons.md +383 -0
- package/skills/sentry/references/sdks/nextjs/error-monitoring.md +974 -0
- package/skills/sentry/references/sdks/nextjs/index.md +491 -0
- package/skills/sentry/references/sdks/nextjs/logging.md +381 -0
- package/skills/sentry/references/sdks/nextjs/metrics.md +411 -0
- package/skills/sentry/references/sdks/nextjs/profiling.md +403 -0
- package/skills/sentry/references/sdks/nextjs/session-replay.md +462 -0
- package/skills/sentry/references/sdks/nextjs/tracing.md +628 -0
- package/skills/sentry/references/sdks/node/ai-monitoring.md +303 -0
- package/skills/sentry/references/sdks/node/crons.md +432 -0
- package/skills/sentry/references/sdks/node/error-monitoring.md +1125 -0
- package/skills/sentry/references/sdks/node/index.md +942 -0
- package/skills/sentry/references/sdks/node/logging.md +380 -0
- package/skills/sentry/references/sdks/node/metrics.md +278 -0
- package/skills/sentry/references/sdks/node/profiling.md +373 -0
- package/skills/sentry/references/sdks/node/tracing.md +878 -0
- package/skills/sentry/references/sdks/php/ai-monitoring.md +310 -0
- package/skills/sentry/references/sdks/php/crons.md +265 -0
- package/skills/sentry/references/sdks/php/error-monitoring.md +626 -0
- package/skills/sentry/references/sdks/php/index.md +362 -0
- package/skills/sentry/references/sdks/php/laravel.md +542 -0
- package/skills/sentry/references/sdks/php/logging.md +242 -0
- package/skills/sentry/references/sdks/php/metrics.md +193 -0
- package/skills/sentry/references/sdks/php/profiling.md +115 -0
- package/skills/sentry/references/sdks/php/symfony.md +552 -0
- package/skills/sentry/references/sdks/php/tracing.md +516 -0
- package/skills/sentry/references/sdks/python/ai-monitoring.md +351 -0
- package/skills/sentry/references/sdks/python/crons.md +218 -0
- package/skills/sentry/references/sdks/python/error-monitoring.md +292 -0
- package/skills/sentry/references/sdks/python/index.md +361 -0
- package/skills/sentry/references/sdks/python/logging.md +234 -0
- package/skills/sentry/references/sdks/python/metrics.md +154 -0
- package/skills/sentry/references/sdks/python/profiling.md +120 -0
- package/skills/sentry/references/sdks/python/tracing.md +364 -0
- package/skills/sentry/references/sdks/react/error-monitoring.md +1607 -0
- package/skills/sentry/references/sdks/react/index.md +492 -0
- package/skills/sentry/references/sdks/react/logging.md +364 -0
- package/skills/sentry/references/sdks/react/profiling.md +322 -0
- package/skills/sentry/references/sdks/react/react-features.md +1272 -0
- package/skills/sentry/references/sdks/react/session-replay.md +1193 -0
- package/skills/sentry/references/sdks/react/tracing.md +1415 -0
- package/skills/sentry/references/sdks/react-native/error-monitoring.md +1481 -0
- package/skills/sentry/references/sdks/react-native/expo-config-plugin.md +45 -0
- package/skills/sentry/references/sdks/react-native/index.md +1030 -0
- package/skills/sentry/references/sdks/react-native/logging.md +444 -0
- package/skills/sentry/references/sdks/react-native/profiling.md +386 -0
- package/skills/sentry/references/sdks/react-native/session-replay.md +704 -0
- package/skills/sentry/references/sdks/react-native/tracing.md +1086 -0
- package/skills/sentry/references/sdks/react-native/user-feedback.md +815 -0
- package/skills/sentry/references/sdks/react-router-framework/error-monitoring.md +127 -0
- package/skills/sentry/references/sdks/react-router-framework/index.md +411 -0
- package/skills/sentry/references/sdks/react-router-framework/logging.md +66 -0
- package/skills/sentry/references/sdks/react-router-framework/profiling.md +57 -0
- package/skills/sentry/references/sdks/react-router-framework/react-router-framework-features.md +110 -0
- package/skills/sentry/references/sdks/react-router-framework/session-replay.md +67 -0
- package/skills/sentry/references/sdks/react-router-framework/tracing.md +96 -0
- package/skills/sentry/references/sdks/react-router-framework/user-feedback.md +71 -0
- package/skills/sentry/references/sdks/ruby/crons.md +184 -0
- package/skills/sentry/references/sdks/ruby/error-monitoring.md +248 -0
- package/skills/sentry/references/sdks/ruby/index.md +297 -0
- package/skills/sentry/references/sdks/ruby/logging.md +168 -0
- package/skills/sentry/references/sdks/ruby/metrics.md +196 -0
- package/skills/sentry/references/sdks/ruby/migration.md +321 -0
- package/skills/sentry/references/sdks/ruby/profiling.md +107 -0
- package/skills/sentry/references/sdks/ruby/tracing.md +388 -0
- package/skills/sentry/references/sdks/svelte/error-monitoring.md +456 -0
- package/skills/sentry/references/sdks/svelte/index.md +467 -0
- package/skills/sentry/references/sdks/svelte/logging.md +344 -0
- package/skills/sentry/references/sdks/svelte/session-replay.md +369 -0
- package/skills/sentry/references/sdks/svelte/tracing.md +406 -0
- package/skills/sentry/references/sdks/tanstack-start/error-monitoring.md +149 -0
- package/skills/sentry/references/sdks/tanstack-start/index.md +381 -0
- package/skills/sentry/references/sdks/tanstack-start/logging.md +74 -0
- package/skills/sentry/references/sdks/tanstack-start/session-replay.md +76 -0
- package/skills/sentry/references/sdks/tanstack-start/tanstackstart-features.md +128 -0
- package/skills/sentry/references/sdks/tanstack-start/tracing.md +123 -0
- package/skills/sentry/references/sdks/tanstack-start/user-feedback.md +81 -0
- package/skills/sentry/references/search-query-language.md +226 -0
- package/skills/sentry/references/semantics/angular.md +7 -0
- package/skills/sentry/references/semantics/app.md +28 -0
- package/skills/sentry/references/semantics/art.md +17 -0
- package/skills/sentry/references/semantics/aws.md +43 -0
- package/skills/sentry/references/semantics/browser.md +34 -0
- package/skills/sentry/references/semantics/cache.md +12 -0
- package/skills/sentry/references/semantics/client.md +8 -0
- package/skills/sentry/references/semantics/cloud.md +12 -0
- package/skills/sentry/references/semantics/cloudflare.md +23 -0
- package/skills/sentry/references/semantics/code.md +11 -0
- package/skills/sentry/references/semantics/culture.md +11 -0
- package/skills/sentry/references/semantics/db.md +21 -0
- package/skills/sentry/references/semantics/device.md +43 -0
- package/skills/sentry/references/semantics/error.md +7 -0
- package/skills/sentry/references/semantics/event.md +8 -0
- package/skills/sentry/references/semantics/exception.md +10 -0
- package/skills/sentry/references/semantics/faas.md +19 -0
- package/skills/sentry/references/semantics/file.md +8 -0
- package/skills/sentry/references/semantics/flag.md +7 -0
- package/skills/sentry/references/semantics/gcp.md +16 -0
- package/skills/sentry/references/semantics/gen_ai.md +53 -0
- package/skills/sentry/references/semantics/general.md +11 -0
- package/skills/sentry/references/semantics/graphql.md +9 -0
- package/skills/sentry/references/semantics/grpc.md +19 -0
- package/skills/sentry/references/semantics/http.md +34 -0
- package/skills/sentry/references/semantics/index.md +63 -0
- package/skills/sentry/references/semantics/jsonrpc.md +8 -0
- package/skills/sentry/references/semantics/jvm.md +12 -0
- package/skills/sentry/references/semantics/koa.md +7 -0
- package/skills/sentry/references/semantics/logger.md +7 -0
- package/skills/sentry/references/semantics/mcp.md +37 -0
- package/skills/sentry/references/semantics/mdc.md +7 -0
- package/skills/sentry/references/semantics/messaging.md +23 -0
- package/skills/sentry/references/semantics/middleware.md +7 -0
- package/skills/sentry/references/semantics/navigation.md +9 -0
- package/skills/sentry/references/semantics/nel.md +11 -0
- package/skills/sentry/references/semantics/network.md +17 -0
- package/skills/sentry/references/semantics/os.md +15 -0
- package/skills/sentry/references/semantics/otel.md +10 -0
- package/skills/sentry/references/semantics/params.md +7 -0
- package/skills/sentry/references/semantics/process.md +14 -0
- package/skills/sentry/references/semantics/react.md +7 -0
- package/skills/sentry/references/semantics/remix.md +7 -0
- package/skills/sentry/references/semantics/resource.md +7 -0
- package/skills/sentry/references/semantics/rpc.md +10 -0
- package/skills/sentry/references/semantics/score.md +10 -0
- package/skills/sentry/references/semantics/sentry.md +69 -0
- package/skills/sentry/references/semantics/server.md +8 -0
- package/skills/sentry/references/semantics/service.md +8 -0
- package/skills/sentry/references/semantics/session.md +7 -0
- package/skills/sentry/references/semantics/state.md +7 -0
- package/skills/sentry/references/semantics/thread.md +8 -0
- package/skills/sentry/references/semantics/timber.md +7 -0
- package/skills/sentry/references/semantics/trpc.md +8 -0
- package/skills/sentry/references/semantics/ui.md +18 -0
- package/skills/sentry/references/semantics/url.md +15 -0
- package/skills/sentry/references/semantics/user.md +17 -0
- package/skills/sentry/references/semantics/user_agent.md +7 -0
- package/skills/sentry/references/semantics/vercel.md +42 -0
- package/skills/sentry/references/setup-verification.md +39 -0
- package/skills/sentry/references/snapshots/github-actions-fanout.md +206 -0
- package/skills/sentry/references/snapshots/github-actions-simple.md +102 -0
- package/skills/sentry/references/snapshots/github-actions-swift-snapshot-testing.md +118 -0
- package/skills/sentry/references/snapshots/index.md +19 -0
- package/skills/sentry/references/snapshots/snapshot-previews.md +100 -0
- package/skills/sentry/references/snapshots/snapshots.md +123 -0
- package/skills/sentry/references/snapshots/wizard-setup.md +134 -0
- package/skills/testing/LICENSE +21 -0
- package/skills/testing/NOTICE +7 -0
- package/skills/testing/SKILL.md +13 -19
- package/skills/testing/agents/openai.yaml +1 -2
- package/skills/testing/references/selection.md +23 -0
- package/skills/testing/references/tdd.md +19 -0
- package/skills/testing/references/test-design.md +17 -0
- package/src/catalog.ts +1 -7
- package/skills/build-effect-apis/SKILL.md +0 -81
- package/skills/build-effect-apis/agents/openai.yaml +0 -4
- package/skills/build-effect-clis/SKILL.md +0 -92
- package/skills/build-effect-clis/agents/openai.yaml +0 -4
- package/skills/effect-architecture-audit/agents/openai.yaml +0 -4
- package/skills/effect-atom-state/SKILL.md +0 -97
- package/skills/effect-atom-state/agents/openai.yaml +0 -4
- package/skills/effect-ts/SKILL.md +0 -35
- package/skills/effect-ts/agents/openai.yaml +0 -4
- /package/skills/{build-effect-apis/references → effect-development/references/api}/cloudflare-workers.md +0 -0
- /package/skills/{build-effect-apis/references → effect-development/references/api}/runtime-assembly.md +0 -0
- /package/skills/{build-effect-apis/references → effect-development/references/api}/server-and-middleware.md +0 -0
- /package/skills/{build-effect-apis/references → effect-development/references/api}/shared-contracts.md +0 -0
- /package/skills/{effect-architecture-audit/references → effect-development/references/architecture}/service-and-boundary-audit.md +0 -0
- /package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-lifecycle.md +0 -0
- /package/skills/{effect-atom-state/references → effect-development/references/atom}/effect-atom-workflows.md +0 -0
- /package/skills/{effect-atom-state/references → effect-development/references/atom}/tanstack-start.md +0 -0
- /package/skills/{build-effect-clis/references → effect-development/references/cli}/command-design.md +0 -0
- /package/skills/{build-effect-clis/references → effect-development/references/cli}/processes-and-platform.md +0 -0
|
@@ -0,0 +1,729 @@
|
|
|
1
|
+
# Error Monitoring — Sentry NestJS SDK
|
|
2
|
+
|
|
3
|
+
> Minimum SDK: `@sentry/nestjs` ≥8.0.0\
|
|
4
|
+
> `@SentryTraced()` requires ≥8.15.0 · `@SentryCron()` requires ≥8.16.0 · Event Emitter
|
|
5
|
+
> auto-instrumentation requires ≥8.39.0
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## How NestJS Error Capture Works
|
|
10
|
+
|
|
11
|
+
NestJS routes all unhandled exceptions through its **exception filter pipeline** before
|
|
12
|
+
they reach the response.
|
|
13
|
+
This means errors don’t bubble up to Node’s uncaught exception handler — Sentry only
|
|
14
|
+
sees them if you hook into that pipeline.
|
|
15
|
+
|
|
16
|
+
The SDK provides two integration points:
|
|
17
|
+
|
|
18
|
+
| Mechanism | Use When |
|
|
19
|
+
| --------------------------------------- | ------------------------------------------------------- |
|
|
20
|
+
| `SentryGlobalFilter` (via `APP_FILTER`) | You don’t have a custom catch-all filter |
|
|
21
|
+
| `@SentryExceptionCaptured()` decorator | You have an existing `@Catch()` filter you want to keep |
|
|
22
|
+
|
|
23
|
+
Both internally use `isExpectedError()` — a duck-typing check that skips `HttpException`
|
|
24
|
+
(4xx) and `RpcException` so only unexpected errors are reported.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Exception Filter Setup
|
|
29
|
+
|
|
30
|
+
### Pattern A: `SentryGlobalFilter` (recommended for most apps)
|
|
31
|
+
|
|
32
|
+
Register the filter globally in `AppModule`. It automatically handles HTTP, GraphQL, and
|
|
33
|
+
RPC contexts.
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// app.module.ts
|
|
37
|
+
import { Module } from "@nestjs/common";
|
|
38
|
+
import { APP_FILTER } from "@nestjs/core";
|
|
39
|
+
import { SentryModule } from "@sentry/nestjs/setup";
|
|
40
|
+
import { SentryGlobalFilter } from "@sentry/nestjs/setup";
|
|
41
|
+
|
|
42
|
+
@Module({
|
|
43
|
+
imports: [SentryModule.forRoot()],
|
|
44
|
+
providers: [
|
|
45
|
+
{
|
|
46
|
+
provide: APP_FILTER,
|
|
47
|
+
useClass: SentryGlobalFilter,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
})
|
|
51
|
+
export class AppModule {}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
> **Import path matters:** `SentryGlobalFilter` and `SentryModule` come from
|
|
55
|
+
> `@sentry/nestjs/setup`, not `@sentry/nestjs`. This separation ensures they’re loaded
|
|
56
|
+
> after `Sentry.init()` runs (in `instrument.ts`), so OpenTelemetry instrumentation can
|
|
57
|
+
> patch NestJS before it’s imported.
|
|
58
|
+
|
|
59
|
+
### Pattern B: Decorate an existing catch-all filter
|
|
60
|
+
|
|
61
|
+
If you already have a `@Catch()` filter, add `@SentryExceptionCaptured()` to its `catch`
|
|
62
|
+
method instead of registering `SentryGlobalFilter`:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { Catch, ExceptionFilter, ArgumentsHost } from "@nestjs/common";
|
|
66
|
+
import { SentryExceptionCaptured } from "@sentry/nestjs";
|
|
67
|
+
|
|
68
|
+
@Catch()
|
|
69
|
+
export class GlobalExceptionFilter implements ExceptionFilter {
|
|
70
|
+
@SentryExceptionCaptured() // ← captures before your handler runs
|
|
71
|
+
catch(exception: unknown, host: ArgumentsHost): void {
|
|
72
|
+
// your existing error handling logic
|
|
73
|
+
// Sentry capture already happened via the decorator
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Pattern C: Per-exception-type filter with manual capture
|
|
79
|
+
|
|
80
|
+
For filters scoped to a specific exception type, call `Sentry.captureException()`
|
|
81
|
+
explicitly:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { Catch, ArgumentsHost, BadRequestException } from "@nestjs/common";
|
|
85
|
+
import { BaseExceptionFilter } from "@nestjs/core";
|
|
86
|
+
import * as Sentry from "@sentry/nestjs";
|
|
87
|
+
|
|
88
|
+
@Catch(DatabaseException)
|
|
89
|
+
export class DatabaseExceptionFilter extends BaseExceptionFilter {
|
|
90
|
+
catch(exception: DatabaseException, host: ArgumentsHost) {
|
|
91
|
+
Sentry.captureException(exception, {
|
|
92
|
+
tags: { component: "database", query: exception.query },
|
|
93
|
+
});
|
|
94
|
+
return super.catch(new BadRequestException(exception.message), host);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## What Is (and Isn’t) Captured Automatically
|
|
102
|
+
|
|
103
|
+
### HTTP context
|
|
104
|
+
|
|
105
|
+
| Error Type | Captured? | Reason |
|
|
106
|
+
| -------------------------------------------------------- | --------- | ------------------------------- |
|
|
107
|
+
| Unhandled exceptions from controllers | ✅ Yes | `SentryGlobalFilter` intercepts |
|
|
108
|
+
| `HttpException` (4xx errors) | ❌ No | `isExpectedError()` skips them |
|
|
109
|
+
| `HttpException` subclasses (`BadRequestException`, etc.) | ❌ No | Duck-typed as expected |
|
|
110
|
+
| Caught + swallowed in service `try/catch` | ❌ No | Never reaches the filter |
|
|
111
|
+
| Re-thrown from `try/catch` | ✅ Yes | Reaches filter as unhandled |
|
|
112
|
+
|
|
113
|
+
### GraphQL context
|
|
114
|
+
|
|
115
|
+
`SentryGlobalFilter` detects `host.getType<string>() === 'graphql'` and adjusts
|
|
116
|
+
behavior:
|
|
117
|
+
|
|
118
|
+
- `HttpException` → re-thrown without capture (expected, NestJS handles formatting)
|
|
119
|
+
- Any other `Error` → captured **and** re-thrown (so GraphQL can format the error
|
|
120
|
+
response)
|
|
121
|
+
- Non-`Error` objects → captured **and** re-thrown
|
|
122
|
+
|
|
123
|
+
> GraphQL errors are always re-thrown so the Apollo/Mercurius error formatter can run.
|
|
124
|
+
> This means they appear in Sentry **and** in the GraphQL error response.
|
|
125
|
+
|
|
126
|
+
### RPC / Microservices context
|
|
127
|
+
|
|
128
|
+
`SentryGlobalFilter` handles RPC but logs a warning recommending a dedicated filter:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
IMPORTANT: RpcException should be handled with a dedicated Rpc exception filter, not the generic SentryGlobalFilter
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
For production microservices, use a dedicated RPC filter:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { Catch, RpcExceptionFilter, ArgumentsHost } from "@nestjs/common";
|
|
138
|
+
import { Observable, throwError } from "rxjs";
|
|
139
|
+
import { RpcException } from "@nestjs/microservices";
|
|
140
|
+
import * as Sentry from "@sentry/nestjs";
|
|
141
|
+
|
|
142
|
+
@Catch(RpcException)
|
|
143
|
+
export class SentryRpcExceptionFilter implements RpcExceptionFilter<RpcException> {
|
|
144
|
+
catch(exception: RpcException, host: ArgumentsHost): Observable<any> {
|
|
145
|
+
Sentry.captureException(exception);
|
|
146
|
+
return throwError(() => exception.getError());
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### The Core Rule
|
|
152
|
+
|
|
153
|
+
> **“Caught exceptions never reach the filter.
|
|
154
|
+
> If you catch and swallow an error, Sentry never sees it.”**
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// ✅ Automatically captured — reaches SentryGlobalFilter
|
|
158
|
+
throw new Error("Unhandled database error");
|
|
159
|
+
|
|
160
|
+
// ✅ Automatically captured — re-thrown reaches filter
|
|
161
|
+
try {
|
|
162
|
+
await db.query(sql);
|
|
163
|
+
} catch (err) {
|
|
164
|
+
throw err; // or: throw new InternalServerErrorException(err.message)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ❌ NOT captured — swallowed before reaching filter
|
|
168
|
+
try {
|
|
169
|
+
await db.query(sql);
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return { error: "Query failed" }; // ← must add captureException here
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ✅ Manually captured before graceful return
|
|
175
|
+
try {
|
|
176
|
+
await db.query(sql);
|
|
177
|
+
} catch (err) {
|
|
178
|
+
Sentry.captureException(err);
|
|
179
|
+
return { error: "Query failed" };
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Manual Error Capture
|
|
186
|
+
|
|
187
|
+
### `Sentry.captureException(error, context?)`
|
|
188
|
+
|
|
189
|
+
Captures an exception immediately, regardless of the filter pipeline.
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import * as Sentry from "@sentry/nestjs";
|
|
193
|
+
|
|
194
|
+
// Basic
|
|
195
|
+
Sentry.captureException(new Error("Payment processing failed"));
|
|
196
|
+
|
|
197
|
+
// With inline context (one-off enrichment — doesn't affect other events)
|
|
198
|
+
Sentry.captureException(error, {
|
|
199
|
+
level: "fatal",
|
|
200
|
+
tags: { component: "payments", provider: "stripe" },
|
|
201
|
+
extra: { orderId, customerId },
|
|
202
|
+
user: { id: req.user.id, email: req.user.email },
|
|
203
|
+
fingerprint: ["payment-failure", String(error.code)],
|
|
204
|
+
contexts: {
|
|
205
|
+
order: { id: orderId, total: 9900, currency: "USD" },
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### `Sentry.captureMessage(message, levelOrContext?)`
|
|
211
|
+
|
|
212
|
+
Captures a plain message — useful for notable conditions that aren’t exceptions.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// With severity level
|
|
216
|
+
Sentry.captureMessage("Deprecated API version used", "warning");
|
|
217
|
+
// Levels: "fatal" | "error" | "warning" | "log" | "info" | "debug"
|
|
218
|
+
|
|
219
|
+
// With full context
|
|
220
|
+
Sentry.captureMessage("Cache miss rate above threshold", {
|
|
221
|
+
level: "warning",
|
|
222
|
+
tags: { cache: "redis", key_pattern: "user:*" },
|
|
223
|
+
extra: { missRate: 0.42, threshold: 0.2 },
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## How `isExpectedError()` Works
|
|
230
|
+
|
|
231
|
+
The SDK uses duck-typing — not `instanceof` — to determine if an error is “expected”
|
|
232
|
+
(should not be reported).
|
|
233
|
+
This is intentional: importing `@nestjs/common` in the main entry point would load it
|
|
234
|
+
before OpenTelemetry can patch it, breaking automatic instrumentation.
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
// Internal SDK logic (simplified)
|
|
238
|
+
function isExpectedError(exception: unknown): boolean {
|
|
239
|
+
if (typeof exception !== "object" || exception === null) return false;
|
|
240
|
+
|
|
241
|
+
const ex = exception as Record<string, unknown>;
|
|
242
|
+
|
|
243
|
+
// HttpException: has getStatus(), getResponse(), initMessage()
|
|
244
|
+
if (
|
|
245
|
+
typeof ex.getStatus === "function" &&
|
|
246
|
+
typeof ex.getResponse === "function" &&
|
|
247
|
+
typeof ex.initMessage === "function"
|
|
248
|
+
) {
|
|
249
|
+
return true; // ← skipped, not reported
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// RpcException: has getError(), initMessage()
|
|
253
|
+
if (typeof ex.getError === "function" && typeof ex.initMessage === "function") {
|
|
254
|
+
return true; // ← skipped, not reported
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return false; // ← reported to Sentry
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Implication:** If you create custom exception classes that mimic these method
|
|
262
|
+
signatures, they will be treated as expected errors and skipped.
|
|
263
|
+
Design your exception hierarchy accordingly.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Scope Management
|
|
268
|
+
|
|
269
|
+
The SDK uses Node’s `AsyncLocalStorage` for automatic request isolation — each HTTP
|
|
270
|
+
request gets its own scope so breadcrumbs and tags from one request don’t contaminate
|
|
271
|
+
another.
|
|
272
|
+
|
|
273
|
+
### Three Scope Levels
|
|
274
|
+
|
|
275
|
+
| Scope | Lifetime | Use for |
|
|
276
|
+
| ------------- | ---------------- | -------------------------------------- |
|
|
277
|
+
| **Global** | Process lifetime | App-wide metadata (version, build SHA) |
|
|
278
|
+
| **Isolation** | One HTTP request | Per-request user, tags |
|
|
279
|
+
| **Current** | One span | Per-span metadata |
|
|
280
|
+
|
|
281
|
+
Precedence when merging: Current > Isolation > Global.
|
|
282
|
+
|
|
283
|
+
### Top-Level Setters Write to Isolation Scope
|
|
284
|
+
|
|
285
|
+
All `Sentry.setXxx()` shorthand methods write to the isolation scope — safe for
|
|
286
|
+
per-request data:
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
// These are equivalent:
|
|
290
|
+
Sentry.setTag("request_id", req.id);
|
|
291
|
+
Sentry.getIsolationScope().setTag("request_id", req.id);
|
|
292
|
+
|
|
293
|
+
// Set user (persists for the current request):
|
|
294
|
+
Sentry.setUser({ id: req.user.id, email: req.user.email });
|
|
295
|
+
|
|
296
|
+
// Clear user:
|
|
297
|
+
Sentry.setUser(null);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Per-Request Enrichment Middleware
|
|
301
|
+
|
|
302
|
+
The recommended pattern for attaching user context to every request:
|
|
303
|
+
|
|
304
|
+
```typescript
|
|
305
|
+
// auth.middleware.ts
|
|
306
|
+
import { Injectable, NestMiddleware } from "@nestjs/common";
|
|
307
|
+
import { Request, Response, NextFunction } from "express";
|
|
308
|
+
import * as Sentry from "@sentry/nestjs";
|
|
309
|
+
|
|
310
|
+
@Injectable()
|
|
311
|
+
export class SentryContextMiddleware implements NestMiddleware {
|
|
312
|
+
use(req: Request, res: Response, next: NextFunction) {
|
|
313
|
+
const user = req.user; // populated by auth guard
|
|
314
|
+
if (user) {
|
|
315
|
+
Sentry.setUser({
|
|
316
|
+
id: String(user.id),
|
|
317
|
+
email: user.email,
|
|
318
|
+
username: user.username,
|
|
319
|
+
});
|
|
320
|
+
Sentry.setTag("user.role", user.role);
|
|
321
|
+
Sentry.setTag("tenant.id", String(user.tenantId));
|
|
322
|
+
}
|
|
323
|
+
next();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Register in `AppModule`:
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
export class AppModule implements NestModule {
|
|
332
|
+
configure(consumer: MiddlewareConsumer) {
|
|
333
|
+
consumer.apply(SentryContextMiddleware).forRoutes("*");
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### `withScope` — Temporary Isolated Context
|
|
339
|
+
|
|
340
|
+
Use `withScope` when you need context on a single capture without affecting other
|
|
341
|
+
events:
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
Sentry.withScope((scope) => {
|
|
345
|
+
scope.setTag("operation", "bulk-import");
|
|
346
|
+
scope.setLevel("warning");
|
|
347
|
+
scope.setContext("import", { rowCount: rows.length, filename });
|
|
348
|
+
scope.setFingerprint(["bulk-import-failure", filename]);
|
|
349
|
+
Sentry.captureException(importError);
|
|
350
|
+
});
|
|
351
|
+
// ← scope above does NOT appear on subsequent events
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Background Job Scope Isolation
|
|
355
|
+
|
|
356
|
+
Background jobs (`@Cron`, `@Interval`, `@OnEvent`, `@Processor`) share the default
|
|
357
|
+
isolation scope with HTTP requests.
|
|
358
|
+
Without isolation, breadcrumbs from a cron job can leak into the next HTTP error event.
|
|
359
|
+
|
|
360
|
+
Wrap with `withIsolationScope()`:
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
import * as Sentry from "@sentry/nestjs";
|
|
364
|
+
import { Injectable } from "@nestjs/common";
|
|
365
|
+
import { Cron, CronExpression } from "@nestjs/schedule";
|
|
366
|
+
|
|
367
|
+
@Injectable()
|
|
368
|
+
export class ReportGenerationService {
|
|
369
|
+
@Cron(CronExpression.EVERY_HOUR)
|
|
370
|
+
async generateReports() {
|
|
371
|
+
await Sentry.withIsolationScope(async () => {
|
|
372
|
+
Sentry.setTag("job", "report-generation");
|
|
373
|
+
Sentry.addBreadcrumb({ message: "Starting report generation", level: "info" });
|
|
374
|
+
try {
|
|
375
|
+
await this.doGenerate();
|
|
376
|
+
} catch (err) {
|
|
377
|
+
Sentry.captureException(err);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Also applies to `@Interval()`, `@OnEvent()`, `@Processor()`, and any other background
|
|
385
|
+
task handler.
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Context Enrichment
|
|
390
|
+
|
|
391
|
+
### Tags (searchable, indexed)
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
Sentry.setTag("page_locale", "de-at");
|
|
395
|
+
Sentry.setTags({
|
|
396
|
+
"feature.flag": "new_checkout_v2",
|
|
397
|
+
"subscription.tier": "enterprise",
|
|
398
|
+
region: "eu-west-1",
|
|
399
|
+
});
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
Constraints: key max 32 chars, value max 200 chars, no newlines.
|
|
403
|
+
|
|
404
|
+
### Context (structured, non-searchable)
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
Sentry.setContext("order", {
|
|
408
|
+
id: orderId,
|
|
409
|
+
items: cart.length,
|
|
410
|
+
total_usd: cart.total,
|
|
411
|
+
coupon: couponCode ?? null,
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Clear a context:
|
|
415
|
+
Sentry.setContext("order", null);
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
> Normalized to 3 levels deep by default.
|
|
419
|
+
> The `type` key is reserved — don’t use it.
|
|
420
|
+
|
|
421
|
+
### User Identity
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
// On authenticated request
|
|
425
|
+
Sentry.setUser({
|
|
426
|
+
id: String(user.id),
|
|
427
|
+
email: user.email,
|
|
428
|
+
username: user.username,
|
|
429
|
+
subscription: user.plan, // arbitrary extra fields accepted
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// On logout or unauthenticated context
|
|
433
|
+
Sentry.setUser(null);
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Tags vs Context — Decision Guide
|
|
437
|
+
|
|
438
|
+
| Feature | Searchable? | Best For |
|
|
439
|
+
| ----------- | ------------ | -------------------------------------- |
|
|
440
|
+
| **Tags** | ✅ Yes | Filtering, grouping, alerting |
|
|
441
|
+
| **Context** | ❌ No | Structured debug info (nested objects) |
|
|
442
|
+
| **User** | ✅ Partially | User attribution and filtering |
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## Breadcrumbs
|
|
447
|
+
|
|
448
|
+
Breadcrumbs are automatically captured for HTTP requests, database queries, and console
|
|
449
|
+
output. Add manual breadcrumbs for business-logic milestones:
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
Sentry.addBreadcrumb({
|
|
453
|
+
category: "auth",
|
|
454
|
+
message: "User authenticated via OAuth2",
|
|
455
|
+
level: "info",
|
|
456
|
+
data: { provider: "google", userId: user.id },
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
Sentry.addBreadcrumb({
|
|
460
|
+
type: "http",
|
|
461
|
+
category: "api.external",
|
|
462
|
+
message: "POST /payments/charge",
|
|
463
|
+
level: "info",
|
|
464
|
+
data: {
|
|
465
|
+
url: "https://api.stripe.com/v1/charges",
|
|
466
|
+
method: "POST",
|
|
467
|
+
status_code: 422,
|
|
468
|
+
},
|
|
469
|
+
});
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### `beforeBreadcrumb` — Filter or Mutate
|
|
473
|
+
|
|
474
|
+
```typescript
|
|
475
|
+
Sentry.init({
|
|
476
|
+
beforeBreadcrumb(breadcrumb, hint) {
|
|
477
|
+
// Drop verbose DB health-check queries
|
|
478
|
+
if (breadcrumb.category === "db.query" && breadcrumb.message?.includes("SELECT 1")) {
|
|
479
|
+
return null;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Truncate large query strings
|
|
483
|
+
if (breadcrumb.category === "db.query" && breadcrumb.message) {
|
|
484
|
+
breadcrumb.message = breadcrumb.message.slice(0, 200);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return breadcrumb;
|
|
488
|
+
},
|
|
489
|
+
maxBreadcrumbs: 50, // default: 100
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## `beforeSend` and Filtering Hooks
|
|
496
|
+
|
|
497
|
+
### `beforeSend` — Modify or Drop Error Events
|
|
498
|
+
|
|
499
|
+
Last chance to modify or discard events.
|
|
500
|
+
Return `null` to drop the event entirely.
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
Sentry.init({
|
|
504
|
+
dsn: "...",
|
|
505
|
+
beforeSend(event, hint) {
|
|
506
|
+
const error = hint.originalException;
|
|
507
|
+
|
|
508
|
+
// Drop known non-actionable errors
|
|
509
|
+
if (error instanceof Error && error.message.includes("ECONNRESET")) {
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Scrub PII from user context
|
|
514
|
+
if (event.user?.email) {
|
|
515
|
+
event.user = { ...event.user, email: "[filtered]" };
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Scrub Authorization headers
|
|
519
|
+
const headers = event.request?.headers as Record<string, string> | undefined;
|
|
520
|
+
if (headers?.["authorization"]) {
|
|
521
|
+
headers["authorization"] = "[filtered]";
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return event;
|
|
525
|
+
},
|
|
526
|
+
});
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### `ignoreErrors` — Pattern-Based Filtering
|
|
530
|
+
|
|
531
|
+
```typescript
|
|
532
|
+
Sentry.init({
|
|
533
|
+
ignoreErrors: ["ECONNRESET", /^Connection refused$/i, /^ETIMEDOUT/],
|
|
534
|
+
});
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### `beforeSendTransaction` — Filter Performance Events
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
Sentry.init({
|
|
541
|
+
beforeSendTransaction(event) {
|
|
542
|
+
// Drop health check transactions
|
|
543
|
+
if (event.transaction === "GET /health") return null;
|
|
544
|
+
return event;
|
|
545
|
+
},
|
|
546
|
+
});
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## Fingerprinting and Custom Grouping
|
|
552
|
+
|
|
553
|
+
All events have a fingerprint.
|
|
554
|
+
Events with the same fingerprint group into the same Sentry issue.
|
|
555
|
+
|
|
556
|
+
### Per-Capture Fingerprinting
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
// Via captureException context argument
|
|
560
|
+
Sentry.captureException(error, {
|
|
561
|
+
fingerprint: ["database-connection-error", error.code],
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
// Via withScope
|
|
565
|
+
Sentry.withScope((scope) => {
|
|
566
|
+
scope.setFingerprint(["payment-failure", "stripe", String(error.statusCode)]);
|
|
567
|
+
Sentry.captureException(error);
|
|
568
|
+
});
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### `beforeSend` Fingerprinting
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
Sentry.init({
|
|
575
|
+
beforeSend(event, hint) {
|
|
576
|
+
const error = hint.originalException;
|
|
577
|
+
|
|
578
|
+
// All DB connection errors → one issue:
|
|
579
|
+
if (error instanceof DatabaseConnectionError) {
|
|
580
|
+
event.fingerprint = ["database-connection-error"];
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// Extend default grouping (keep stack-trace hash + add dimension):
|
|
584
|
+
if (error instanceof ExternalApiError) {
|
|
585
|
+
event.fingerprint = ["{{ default }}", error.serviceName, String(error.statusCode)];
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
return event;
|
|
589
|
+
},
|
|
590
|
+
});
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Template Variables
|
|
594
|
+
|
|
595
|
+
| Variable | Description |
|
|
596
|
+
| ------------------- | ------------------------------------------------------------ |
|
|
597
|
+
| `{{ default }}` | Sentry’s normally computed hash (extend rather than replace) |
|
|
598
|
+
| `{{ transaction }}` | Current transaction/route name |
|
|
599
|
+
| `{{ type }}` | Exception class name |
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
## Event Processors
|
|
604
|
+
|
|
605
|
+
Unlike `beforeSend` (one allowed), multiple event processors can be registered:
|
|
606
|
+
|
|
607
|
+
```typescript
|
|
608
|
+
// Global — runs for every event
|
|
609
|
+
Sentry.addEventProcessor((event, hint) => {
|
|
610
|
+
event.extra = {
|
|
611
|
+
...event.extra,
|
|
612
|
+
buildSha: process.env.GIT_COMMIT_SHA,
|
|
613
|
+
nodeVersion: process.version,
|
|
614
|
+
};
|
|
615
|
+
return event;
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
// Scoped — only for a specific capture
|
|
619
|
+
Sentry.withScope((scope) => {
|
|
620
|
+
scope.addEventProcessor((event) => {
|
|
621
|
+
event.tags = { ...event.tags, processed_by: "payment_service" };
|
|
622
|
+
return event;
|
|
623
|
+
});
|
|
624
|
+
Sentry.captureException(paymentError);
|
|
625
|
+
});
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
**Execution order:** All `addEventProcessor()` callbacks run first, then `beforeSend`
|
|
629
|
+
runs last.
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
## Configuration Reference
|
|
634
|
+
|
|
635
|
+
Key `Sentry.init()` options for error monitoring (in `instrument.ts`):
|
|
636
|
+
|
|
637
|
+
| Option | Type | Default | Purpose |
|
|
638
|
+
| ----------------------- | ------------------------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
639
|
+
| `dsn` | `string` | env `SENTRY_DSN` | Project identifier; SDK disabled if empty |
|
|
640
|
+
| `environment` | `string` | `"production"` | Deployment environment tag |
|
|
641
|
+
| `release` | `string` | env `SENTRY_RELEASE` | App version string |
|
|
642
|
+
| `sampleRate` | `number` | `1.0` | Fraction of error events to send (0.0–1.0) |
|
|
643
|
+
| `dataCollection` | `object` | conservative unless set | Fine-grained control over auto-collected categories (`userInfo`, `cookies`, `httpHeaders`, `httpBodies`, `queryParams`, `genAI`). When omitted, the SDK falls back to `sendDefaultPii` (default `false`). Passing the object — even `{}` — flips unset categories to their permissive defaults; opt out per category. |
|
|
644
|
+
| `attachStacktrace` | `boolean` | `false` | Add stack traces to `captureMessage()` |
|
|
645
|
+
| `maxBreadcrumbs` | `number` | `100` | Max breadcrumbs per event |
|
|
646
|
+
| `ignoreErrors` | `Array<string \| RegExp>` | `[]` | Error message patterns to never report |
|
|
647
|
+
| `beforeSend` | `(event, hint) => event \| null` | — | Mutate or drop error events before sending |
|
|
648
|
+
| `beforeBreadcrumb` | `(breadcrumb, hint?) => breadcrumb \| null` | — | Mutate or drop breadcrumbs |
|
|
649
|
+
| `includeLocalVariables` | `boolean` | `false` | Capture stack-frame local variable values |
|
|
650
|
+
| `debug` | `boolean` | `false` | Enable SDK debug logging |
|
|
651
|
+
|
|
652
|
+
---
|
|
653
|
+
|
|
654
|
+
## Error Capture Scenario Reference
|
|
655
|
+
|
|
656
|
+
| Scenario | Auto Captured? | Solution |
|
|
657
|
+
| ------------------------------------ | -------------- | ------------------------------------------------- |
|
|
658
|
+
| Unhandled controller exception | ✅ Yes | `SentryGlobalFilter` intercepts |
|
|
659
|
+
| `HttpException` (4xx, 5xx) | ❌ No | Expected by design; capture manually if needed |
|
|
660
|
+
| `try/catch` with graceful return | ❌ No | `Sentry.captureException()` before return |
|
|
661
|
+
| `try/catch` with re-throw | ✅ Yes | Reaches filter as unhandled |
|
|
662
|
+
| GraphQL resolver error | ✅ Yes | `SentryGlobalFilter` captures + re-throws |
|
|
663
|
+
| RPC microservice error | ⚠️ Partial | Use dedicated `RpcExceptionFilter` |
|
|
664
|
+
| Background job (`@Cron`, `@OnEvent`) | ❌ No | Wrap with `withIsolationScope()` + manual capture |
|
|
665
|
+
| WebSocket gateway error | ❌ No | Catch manually in gateway methods |
|
|
666
|
+
| Caught + swallowed error | ❌ No | Always call `captureException` before swallowing |
|
|
667
|
+
|
|
668
|
+
---
|
|
669
|
+
|
|
670
|
+
## API Quick Reference
|
|
671
|
+
|
|
672
|
+
```typescript
|
|
673
|
+
// ── Exception Filter Setup ─────────────────────────────────────────────
|
|
674
|
+
import { SentryGlobalFilter } from "@sentry/nestjs/setup" // APP_FILTER token
|
|
675
|
+
import { SentryExceptionCaptured } from "@sentry/nestjs" // decorator for catch()
|
|
676
|
+
|
|
677
|
+
// ── Capture ───────────────────────────────────────────────────────────
|
|
678
|
+
Sentry.captureException(error)
|
|
679
|
+
Sentry.captureException(error, { level, tags, extra, contexts, fingerprint, user })
|
|
680
|
+
Sentry.captureMessage("text", "warning")
|
|
681
|
+
Sentry.captureMessage("text", { level, tags, extra })
|
|
682
|
+
|
|
683
|
+
// ── User ──────────────────────────────────────────────────────────────
|
|
684
|
+
Sentry.setUser({ id, email, username, ...custom })
|
|
685
|
+
Sentry.setUser(null) // clear on logout
|
|
686
|
+
|
|
687
|
+
// ── Tags (searchable, indexed) ────────────────────────────────────────
|
|
688
|
+
Sentry.setTag("key", "value")
|
|
689
|
+
Sentry.setTags({ key1: "v1", key2: "v2" })
|
|
690
|
+
|
|
691
|
+
// ── Context (structured, non-searchable) ─────────────────────────────
|
|
692
|
+
Sentry.setContext("name", { key: value })
|
|
693
|
+
Sentry.setContext("name", null) // clear
|
|
694
|
+
|
|
695
|
+
// ── Breadcrumbs ───────────────────────────────────────────────────────
|
|
696
|
+
Sentry.addBreadcrumb({ type, category, message, level, data })
|
|
697
|
+
|
|
698
|
+
// ── Scopes ────────────────────────────────────────────────────────────
|
|
699
|
+
Sentry.withScope((scope) => { scope.setTag(...); Sentry.captureException(...) })
|
|
700
|
+
Sentry.withIsolationScope((scope) => { ... }) // background jobs
|
|
701
|
+
Sentry.getGlobalScope().setTag(...)
|
|
702
|
+
Sentry.getIsolationScope().setTag(...) // same as Sentry.setTag()
|
|
703
|
+
|
|
704
|
+
// ── Fingerprinting ────────────────────────────────────────────────────
|
|
705
|
+
scope.setFingerprint(["group-key"])
|
|
706
|
+
event.fingerprint = ["{{ default }}", "extra-dimension"] // in beforeSend
|
|
707
|
+
|
|
708
|
+
// ── Hooks ─────────────────────────────────────────────────────────────
|
|
709
|
+
Sentry.init({ beforeSend(event, hint) { return event | null } })
|
|
710
|
+
Sentry.init({ beforeSendTransaction(event) { return event | null } })
|
|
711
|
+
Sentry.init({ beforeBreadcrumb(breadcrumb, hint) { return breadcrumb | null } })
|
|
712
|
+
Sentry.init({ ignoreErrors: ["string", /regex/] })
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
---
|
|
716
|
+
|
|
717
|
+
## Troubleshooting
|
|
718
|
+
|
|
719
|
+
| Issue | Solution |
|
|
720
|
+
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
721
|
+
| `HttpException` errors not appearing | Expected — by design. Call `Sentry.captureException()` manually if you want 4xx/5xx reported |
|
|
722
|
+
| Unhandled controller errors not appearing | Ensure `SentryGlobalFilter` is registered via `APP_FILTER` in `AppModule`, and `SentryModule.forRoot()` is in imports |
|
|
723
|
+
| Breadcrumbs from cron jobs appearing in HTTP errors | Wrap cron/event handlers with `Sentry.withIsolationScope()` |
|
|
724
|
+
| GraphQL errors not appearing | `SentryGlobalFilter` handles this automatically — verify it’s registered. Check if a custom exception filter intercepts before `SentryGlobalFilter` runs |
|
|
725
|
+
| RPC errors appear with a warning | Use a dedicated `@Catch(RpcException)` filter and call `Sentry.captureException()` explicitly |
|
|
726
|
+
| User context missing from events | Set `Sentry.setUser()` in middleware **before** the request reaches the controller; isolation scope is per-request |
|
|
727
|
+
| `instrument.ts` import order error | `import "./instrument"` must be the **very first line** of `main.ts` — before any other imports |
|
|
728
|
+
| Events not appearing | Verify DSN, enable `debug: true` in `Sentry.init()` to see SDK logs, confirm `SentryModule.forRoot()` is imported |
|
|
729
|
+
| PII appearing in events | Data is collected by default; opt out via `dataCollection` (e.g. `userInfo: false`, `httpBodies: []`, `cookies: false`) and scrub remaining values in `beforeSend` |
|