@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,1125 @@
|
|
|
1
|
+
# Error Monitoring — Sentry Node.js SDK
|
|
2
|
+
|
|
3
|
+
> Minimum SDK: `@sentry/node` ≥8.0.0\
|
|
4
|
+
> NestJS integration: `@sentry/nestjs` ≥8.0.0\
|
|
5
|
+
> Bun integration: `@sentry/bun` ≥8.0.0 (thin wrapper over `@sentry/node`)\
|
|
6
|
+
> Deno integration: `npm:@sentry/deno` (Deno 2+)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## The Instrument-First Rule
|
|
11
|
+
|
|
12
|
+
`@sentry/node` patches modules at import time via OpenTelemetry.
|
|
13
|
+
The instrument file **must be loaded before everything else** — before your framework,
|
|
14
|
+
before your database driver, before any HTTP client.
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
// instrument.js — loaded first
|
|
18
|
+
const Sentry = require("@sentry/node");
|
|
19
|
+
|
|
20
|
+
Sentry.init({
|
|
21
|
+
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
22
|
+
release: "my-app@1.2.3",
|
|
23
|
+
environment: process.env.NODE_ENV ?? "production",
|
|
24
|
+
tracesSampleRate: 1.0,
|
|
25
|
+
dataCollection: {
|
|
26
|
+
// To disable sending user data and HTTP bodies, uncomment the lines below. For more info visit:
|
|
27
|
+
// https://docs.sentry.io/platforms/javascript/guides/node/configuration/options/#dataCollection
|
|
28
|
+
// userInfo: false,
|
|
29
|
+
// httpBodies: [],
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
// app.js
|
|
36
|
+
require("./instrument"); // MUST be line 1
|
|
37
|
+
const express = require("express");
|
|
38
|
+
// ...
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**ESM (Node 18.19+ / 19.9+):**
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
// instrument.mjs
|
|
45
|
+
import * as Sentry from "@sentry/node";
|
|
46
|
+
Sentry.init({ dsn: "...", tracesSampleRate: 1.0 });
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Launch with --import
|
|
51
|
+
node --import ./instrument.mjs app.mjs
|
|
52
|
+
# or:
|
|
53
|
+
NODE_OPTIONS="--import ./instrument.mjs" npm start
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## What Is Captured Automatically
|
|
59
|
+
|
|
60
|
+
| Error Type | Captured? | Mechanism |
|
|
61
|
+
| ------------------------------------------------------- | --------- | ------------------------------------- |
|
|
62
|
+
| Uncaught exceptions | ✅ Yes | `process.on("uncaughtException")` |
|
|
63
|
+
| Unhandled promise rejections | ✅ Yes | `process.on("unhandledRejection")` |
|
|
64
|
+
| Framework errors (Express, Fastify, Koa, Hapi, Connect) | ✅ Yes | Error handler middleware (see below) |
|
|
65
|
+
| NestJS non-HttpExceptions | ✅ Yes | `SentryGlobalFilter` |
|
|
66
|
+
| Caught + re-thrown errors | ✅ Yes | Bubbles to global handler |
|
|
67
|
+
| Caught + swallowed errors | ❌ No | Must call `captureException` manually |
|
|
68
|
+
| `HttpException` in NestJS (4xx) | ❌ No | Treated as control flow by design |
|
|
69
|
+
|
|
70
|
+
### The Core Rule
|
|
71
|
+
|
|
72
|
+
> **“If you catch an error and don’t re-throw it, Sentry never sees it.”**
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
// ✅ Auto-captured — unhandled, bubbles up
|
|
76
|
+
throw new Error("Unhandled");
|
|
77
|
+
|
|
78
|
+
// ✅ Auto-captured — re-thrown
|
|
79
|
+
try {
|
|
80
|
+
await doSomething();
|
|
81
|
+
} catch (err) {
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ❌ NOT captured — swallowed by graceful return
|
|
86
|
+
try {
|
|
87
|
+
await doSomething();
|
|
88
|
+
} catch (err) {
|
|
89
|
+
return res.status(500).json({ error: "Failed" }); // ← add captureException!
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ✅ Manually captured
|
|
93
|
+
try {
|
|
94
|
+
await doSomething();
|
|
95
|
+
} catch (err) {
|
|
96
|
+
Sentry.captureException(err);
|
|
97
|
+
return res.status(500).json({ error: "Failed" });
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Framework Error Handler Placement
|
|
104
|
+
|
|
105
|
+
**Critical: placement rules differ per framework.
|
|
106
|
+
Getting this wrong silently misses errors.**
|
|
107
|
+
|
|
108
|
+
| Framework | Function | Placement | Async? |
|
|
109
|
+
| --------- | ----------------------------------------------- | -------------------- | ---------------------- |
|
|
110
|
+
| Express | `setupExpressErrorHandler(app)` | **AFTER routes** | No |
|
|
111
|
+
| Fastify | `setupFastifyErrorHandler(app)` | **BEFORE routes** | No |
|
|
112
|
+
| Koa | `setupKoaErrorHandler(app)` | **FIRST middleware** | No |
|
|
113
|
+
| Hapi | `setupHapiErrorHandler(server)` | Before routes | **YES — must `await`** |
|
|
114
|
+
| Connect | `setupConnectErrorHandler(app)` | **BEFORE routes** | No |
|
|
115
|
+
| NestJS | `SentryGlobalFilter` + `SentryModule.forRoot()` | AppModule providers | No |
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Express
|
|
120
|
+
|
|
121
|
+
Error handler goes **after all routes**, before your own error handler.
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
require("./instrument");
|
|
125
|
+
const express = require("express");
|
|
126
|
+
const Sentry = require("@sentry/node");
|
|
127
|
+
|
|
128
|
+
const app = express();
|
|
129
|
+
app.use(express.json());
|
|
130
|
+
|
|
131
|
+
// ── Routes ──────────────────────────────────────────────────────
|
|
132
|
+
app.get("/", (req, res) => res.json({ ok: true }));
|
|
133
|
+
app.post("/orders", async (req, res, next) => {
|
|
134
|
+
try {
|
|
135
|
+
const result = await processOrder(req.body.orderId);
|
|
136
|
+
res.json(result);
|
|
137
|
+
} catch (err) {
|
|
138
|
+
next(err); // pass to error handlers
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// ↓ Sentry AFTER routes, BEFORE your error handler
|
|
143
|
+
Sentry.setupExpressErrorHandler(app);
|
|
144
|
+
|
|
145
|
+
// Optional: capture only specific status codes
|
|
146
|
+
// Sentry.setupExpressErrorHandler(app, {
|
|
147
|
+
// shouldHandleError(error) {
|
|
148
|
+
// return !error.status || parseInt(String(error.status)) >= 500;
|
|
149
|
+
// },
|
|
150
|
+
// });
|
|
151
|
+
|
|
152
|
+
// ── Your error handler (runs after Sentry) ──────────────────────
|
|
153
|
+
app.use((err, req, res, next) => {
|
|
154
|
+
res.status(err.status || 500).json({ error: "Internal Server Error" });
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
app.listen(3000);
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Fastify
|
|
163
|
+
|
|
164
|
+
Error handler goes **before routes**. Internally registers a Fastify plugin using
|
|
165
|
+
`onError` lifecycle hook.
|
|
166
|
+
|
|
167
|
+
```javascript
|
|
168
|
+
require("./instrument");
|
|
169
|
+
const Fastify = require("fastify");
|
|
170
|
+
const Sentry = require("@sentry/node");
|
|
171
|
+
|
|
172
|
+
const app = Fastify({ logger: true });
|
|
173
|
+
|
|
174
|
+
// ↓ Sentry BEFORE routes
|
|
175
|
+
Sentry.setupFastifyErrorHandler(app);
|
|
176
|
+
|
|
177
|
+
// Optional: customize which errors are captured
|
|
178
|
+
// Sentry.setupFastifyErrorHandler(app, {
|
|
179
|
+
// shouldHandleError(error, request, reply) {
|
|
180
|
+
// return reply.statusCode >= 500;
|
|
181
|
+
// },
|
|
182
|
+
// });
|
|
183
|
+
|
|
184
|
+
app.get("/", async (request, reply) => ({ hello: "world" }));
|
|
185
|
+
app.get("/debug-sentry", async () => {
|
|
186
|
+
throw new Error("Test Fastify error!");
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
app.listen({ port: 3000 });
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Koa
|
|
195
|
+
|
|
196
|
+
Error handler goes as the **first `app.use()` call**, before any route.
|
|
197
|
+
|
|
198
|
+
```javascript
|
|
199
|
+
require("./instrument");
|
|
200
|
+
const Koa = require("koa");
|
|
201
|
+
const Router = require("@koa/router");
|
|
202
|
+
const Sentry = require("@sentry/node");
|
|
203
|
+
|
|
204
|
+
const app = new Koa();
|
|
205
|
+
const router = new Router();
|
|
206
|
+
|
|
207
|
+
// ↓ Sentry FIRST middleware
|
|
208
|
+
Sentry.setupKoaErrorHandler(app);
|
|
209
|
+
|
|
210
|
+
router.get("/", async (ctx) => {
|
|
211
|
+
ctx.body = { ok: true };
|
|
212
|
+
});
|
|
213
|
+
router.get("/debug-sentry", async () => {
|
|
214
|
+
throw new Error("Test Koa error!");
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
app.use(router.routes());
|
|
218
|
+
app.use(router.allowedMethods());
|
|
219
|
+
app.listen(3000);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
> **Note:** `setupKoaErrorHandler` has no `shouldHandleError` option — it captures all
|
|
223
|
+
> errors.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Hapi
|
|
228
|
+
|
|
229
|
+
`setupHapiErrorHandler` is **async** — you must `await` it.
|
|
230
|
+
Internally registers a Hapi lifecycle extension on `onPreResponse`.
|
|
231
|
+
|
|
232
|
+
```javascript
|
|
233
|
+
require("./instrument");
|
|
234
|
+
const Sentry = require("@sentry/node");
|
|
235
|
+
const Hapi = require("@hapi/hapi");
|
|
236
|
+
|
|
237
|
+
const init = async () => {
|
|
238
|
+
const server = Hapi.server({ port: 3000, host: "localhost" });
|
|
239
|
+
|
|
240
|
+
// ↓ MUST be awaited!
|
|
241
|
+
await Sentry.setupHapiErrorHandler(server);
|
|
242
|
+
|
|
243
|
+
server.route({
|
|
244
|
+
method: "GET",
|
|
245
|
+
path: "/debug-sentry",
|
|
246
|
+
handler: () => {
|
|
247
|
+
throw new Error("Test Hapi error!");
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
await server.start();
|
|
252
|
+
console.log("Server running on %s", server.info.uri);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
init();
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
> **Caution:** Forgetting `await` silently skips Sentry registration.
|
|
259
|
+
> No error is thrown.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Connect
|
|
264
|
+
|
|
265
|
+
Error handler goes **before routes**.
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
require("./instrument");
|
|
269
|
+
const connect = require("connect");
|
|
270
|
+
const Sentry = require("@sentry/node");
|
|
271
|
+
|
|
272
|
+
const app = connect();
|
|
273
|
+
|
|
274
|
+
// ↓ Sentry BEFORE routes
|
|
275
|
+
Sentry.setupConnectErrorHandler(app);
|
|
276
|
+
|
|
277
|
+
app.use("/", (req, res, next) => {
|
|
278
|
+
res.setHeader("Content-Type", "application/json");
|
|
279
|
+
res.end(JSON.stringify({ hello: "world" }));
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
app.use("/debug-sentry", (req, res, next) => {
|
|
283
|
+
throw new Error("Test Connect error!");
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// Your own error handler (after Sentry)
|
|
287
|
+
app.use((err, req, res, next) => {
|
|
288
|
+
res.statusCode = err.status || 500;
|
|
289
|
+
res.end("Internal Server Error");
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
require("http").createServer(app).listen(3000);
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## NestJS
|
|
298
|
+
|
|
299
|
+
> **NestJS has a dedicated skill: [`nestjs`](../nestjs/index.md)**
|
|
300
|
+
>
|
|
301
|
+
> NestJS uses a separate package (`@sentry/nestjs`) with NestJS-native error handling
|
|
302
|
+
> via `SentryGlobalFilter`, `SentryModule.forRoot()`, `@SentryExceptionCaptured`
|
|
303
|
+
> decorator, and GraphQL/Microservices support.
|
|
304
|
+
> Load that skill for complete NestJS error monitoring setup including `HttpException`
|
|
305
|
+
> filtering, custom filters, and background job isolation.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Vanilla Node.js (`http` Module)
|
|
310
|
+
|
|
311
|
+
No framework integration needed — rely on the global `uncaughtException` /
|
|
312
|
+
`unhandledRejection` handlers plus manual `captureException` for caught errors.
|
|
313
|
+
|
|
314
|
+
```javascript
|
|
315
|
+
require("./instrument");
|
|
316
|
+
const http = require("http");
|
|
317
|
+
const Sentry = require("@sentry/node");
|
|
318
|
+
|
|
319
|
+
const server = http.createServer(async (req, res) => {
|
|
320
|
+
try {
|
|
321
|
+
const data = await handleRequest(req);
|
|
322
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
323
|
+
res.end(JSON.stringify(data));
|
|
324
|
+
} catch (err) {
|
|
325
|
+
Sentry.captureException(err, {
|
|
326
|
+
tags: { path: req.url, method: req.method },
|
|
327
|
+
});
|
|
328
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
329
|
+
res.end(JSON.stringify({ error: "Internal Server Error" }));
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
server.listen(3000);
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## `captureException` — Full API
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
function captureException(
|
|
342
|
+
exception: unknown,
|
|
343
|
+
captureContext?: CaptureContext | ((scope: Scope) => Scope),
|
|
344
|
+
): string; // returns EventId
|
|
345
|
+
|
|
346
|
+
type CaptureContext = Scope | Partial<ScopeContext> | ((scope: Scope) => Scope);
|
|
347
|
+
|
|
348
|
+
interface ScopeContext {
|
|
349
|
+
user?: User;
|
|
350
|
+
level?: "fatal" | "error" | "warning" | "log" | "info" | "debug";
|
|
351
|
+
extra?: Record<string, unknown>;
|
|
352
|
+
tags?: Record<string, Primitive>;
|
|
353
|
+
contexts?: Record<string, Record<string, unknown>>;
|
|
354
|
+
fingerprint?: string[];
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
```javascript
|
|
359
|
+
// Basic
|
|
360
|
+
Sentry.captureException(new Error("Something broke"));
|
|
361
|
+
|
|
362
|
+
// With inline CaptureContext
|
|
363
|
+
Sentry.captureException(error, {
|
|
364
|
+
level: "fatal",
|
|
365
|
+
tags: { order_id: orderId, payment_method: "stripe" },
|
|
366
|
+
user: { id: req.user.id, email: req.user.email },
|
|
367
|
+
extra: { requestBody: req.body, retryCount: 3 },
|
|
368
|
+
fingerprint: ["order-processing-failure", orderId],
|
|
369
|
+
contexts: {
|
|
370
|
+
order: { id: orderId, total: 99.99, currency: "USD" },
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Scope callback form — most flexible
|
|
375
|
+
Sentry.captureException(error, (scope) => {
|
|
376
|
+
scope.setTag("component", "payment");
|
|
377
|
+
scope.setLevel("error");
|
|
378
|
+
scope.setTransactionName("POST /orders");
|
|
379
|
+
return scope; // must return scope
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// Non-Error values are accepted (but stack traces may be synthetic)
|
|
383
|
+
Sentry.captureException("something broke");
|
|
384
|
+
Sentry.captureException({ code: "AUTH_FAILED", userId: 42 });
|
|
385
|
+
|
|
386
|
+
// Capture and use the returned event ID
|
|
387
|
+
const eventId = Sentry.captureException(err);
|
|
388
|
+
res.status(500).json({ error: "Something went wrong", eventId });
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## `captureMessage`
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
function captureMessage(message: string, captureContext?: CaptureContext | SeverityLevel): string; // returns EventId
|
|
397
|
+
|
|
398
|
+
type SeverityLevel = "fatal" | "error" | "warning" | "log" | "info" | "debug";
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
```javascript
|
|
402
|
+
// Basic
|
|
403
|
+
Sentry.captureMessage("Payment gateway timeout");
|
|
404
|
+
|
|
405
|
+
// With severity level shorthand
|
|
406
|
+
Sentry.captureMessage("Disk usage above 90%", "warning");
|
|
407
|
+
Sentry.captureMessage("Cache miss rate critical", "fatal");
|
|
408
|
+
Sentry.captureMessage("User signed up", "info");
|
|
409
|
+
|
|
410
|
+
// With full context
|
|
411
|
+
Sentry.captureMessage("Rate limit exceeded", {
|
|
412
|
+
level: "warning",
|
|
413
|
+
tags: { service: "api-gateway", region: "us-east-1" },
|
|
414
|
+
user: { id: req.user.id },
|
|
415
|
+
extra: { requestsPerMinute: 1500, limit: 1000 },
|
|
416
|
+
fingerprint: ["rate-limit", req.headers["x-client-id"]],
|
|
417
|
+
});
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## Scope Management (v8+ — Hub Removed)
|
|
423
|
+
|
|
424
|
+
In SDK v8, `Hub` is removed.
|
|
425
|
+
Use the three scope types directly.
|
|
426
|
+
|
|
427
|
+
| Scope | Accessor | Lifetime | Use For |
|
|
428
|
+
| ------------- | ---------------------------- | ------------------------------ | ------------------------------- |
|
|
429
|
+
| **Global** | `Sentry.getGlobalScope()` | Process lifetime | App version, region, build ID |
|
|
430
|
+
| **Isolation** | `Sentry.getIsolationScope()` | Per HTTP request (auto-forked) | User identity, request metadata |
|
|
431
|
+
| **Current** | `Sentry.getCurrentScope()` | Narrow/temporary | Per-operation context |
|
|
432
|
+
|
|
433
|
+
**Priority (current wins):** Current > Isolation > Global
|
|
434
|
+
|
|
435
|
+
```javascript
|
|
436
|
+
// All Sentry.setXXX() top-level methods write to the ISOLATION scope
|
|
437
|
+
Sentry.setTag("key", "value");
|
|
438
|
+
// identical to:
|
|
439
|
+
Sentry.getIsolationScope().setTag("key", "value");
|
|
440
|
+
|
|
441
|
+
// Global scope — survives the lifetime of the process
|
|
442
|
+
Sentry.getGlobalScope().setTag("server_region", "eu-west-1");
|
|
443
|
+
Sentry.getGlobalScope().setContext("runtime", {
|
|
444
|
+
name: "node",
|
|
445
|
+
version: process.version,
|
|
446
|
+
});
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### `withScope` — Temporary Per-Capture Context
|
|
450
|
+
|
|
451
|
+
Primary tool for adding context to a single capture without contaminating other events.
|
|
452
|
+
|
|
453
|
+
```javascript
|
|
454
|
+
Sentry.withScope((scope) => {
|
|
455
|
+
scope.setTag("payment_method", "stripe");
|
|
456
|
+
scope.setFingerprint(["stripe-payment-error"]);
|
|
457
|
+
scope.setLevel("error");
|
|
458
|
+
scope.setUser({ id: req.user.id });
|
|
459
|
+
scope.setContext("cart", { items: req.body.items.length });
|
|
460
|
+
scope.addBreadcrumb({ category: "payment", message: "Attempt #3", level: "info" });
|
|
461
|
+
Sentry.captureException(stripeError);
|
|
462
|
+
// All above ONLY applies to this one capture
|
|
463
|
+
});
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### `withIsolationScope` — Full Isolation (Background Jobs)
|
|
467
|
+
|
|
468
|
+
Use for background jobs, workers, and queue processors where you need a completely clean
|
|
469
|
+
scope.
|
|
470
|
+
|
|
471
|
+
```javascript
|
|
472
|
+
Sentry.withIsolationScope(async (scope) => {
|
|
473
|
+
scope.setUser({ id: job.userId });
|
|
474
|
+
scope.setTag("job_type", job.type);
|
|
475
|
+
scope.setTag("job_id", job.id);
|
|
476
|
+
await processJob(job); // all events inside are fully isolated from other jobs
|
|
477
|
+
});
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Scope Decision Guide
|
|
481
|
+
|
|
482
|
+
| Goal | API |
|
|
483
|
+
| ------------------------------------------ | ------------------------------------------------------ |
|
|
484
|
+
| Data on ALL events (app version, build ID) | `Sentry.getGlobalScope().setTag(...)` |
|
|
485
|
+
| Current request data | `Sentry.setTag(...)` (writes to isolation scope) |
|
|
486
|
+
| One specific capture only | `Sentry.withScope((scope) => { ... })` |
|
|
487
|
+
| Background job / worker | `Sentry.withIsolationScope(async (scope) => { ... })` |
|
|
488
|
+
| Inline on a single event | Second arg to `captureException(err, { tags: {...} })` |
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## Context Enrichment
|
|
493
|
+
|
|
494
|
+
### `setTag` / `setTags` — Indexed, Searchable
|
|
495
|
+
|
|
496
|
+
Tags are **indexed** — use them for filtering, grouping, and alerting.
|
|
497
|
+
Key: max 32 chars, `[a-zA-Z0-9_.:−]`. Value: max 200 chars.
|
|
498
|
+
|
|
499
|
+
```javascript
|
|
500
|
+
Sentry.setTag("db_region", "us-east-1");
|
|
501
|
+
Sentry.setTag("feature_flag_new_ui", true);
|
|
502
|
+
Sentry.setTags({
|
|
503
|
+
service: "checkout",
|
|
504
|
+
version: "2.1.4",
|
|
505
|
+
region: "eu",
|
|
506
|
+
});
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### `setContext` — Structured, Non-Searchable
|
|
510
|
+
|
|
511
|
+
Attaches structured data visible in the issue detail view.
|
|
512
|
+
Not indexed. Normalized to 3 levels deep.
|
|
513
|
+
The `type` key is reserved — don’t use it.
|
|
514
|
+
|
|
515
|
+
```javascript
|
|
516
|
+
Sentry.setContext("order", {
|
|
517
|
+
id: orderId,
|
|
518
|
+
total: 99.99,
|
|
519
|
+
currency: "USD",
|
|
520
|
+
coupon: "SAVE20",
|
|
521
|
+
});
|
|
522
|
+
Sentry.setContext("database", {
|
|
523
|
+
host: "postgres.internal",
|
|
524
|
+
query_duration_ms: 4523,
|
|
525
|
+
active_connections: 19,
|
|
526
|
+
});
|
|
527
|
+
Sentry.setContext("order", null); // clear it
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### `setUser` — User Identity
|
|
531
|
+
|
|
532
|
+
```javascript
|
|
533
|
+
// On login (writes to isolation scope — safe per-request)
|
|
534
|
+
Sentry.setUser({
|
|
535
|
+
id: user.id,
|
|
536
|
+
email: user.email,
|
|
537
|
+
username: user.displayName,
|
|
538
|
+
subscription_tier: "pro", // custom fields accepted
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
// On logout
|
|
542
|
+
Sentry.setUser(null);
|
|
543
|
+
|
|
544
|
+
// Express middleware pattern — set per-request
|
|
545
|
+
app.use((req, res, next) => {
|
|
546
|
+
if (req.user) {
|
|
547
|
+
Sentry.setUser({ id: req.user.id, email: req.user.email });
|
|
548
|
+
}
|
|
549
|
+
next();
|
|
550
|
+
});
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### `setExtra` / `setExtras` — Arbitrary Data
|
|
554
|
+
|
|
555
|
+
Non-indexed supplementary data.
|
|
556
|
+
Prefer `setContext` for structured objects.
|
|
557
|
+
|
|
558
|
+
```javascript
|
|
559
|
+
Sentry.setExtra("server_memory_mb", process.memoryUsage().heapUsed / 1024 / 1024);
|
|
560
|
+
Sentry.setExtras({
|
|
561
|
+
uptime: process.uptime(),
|
|
562
|
+
node_version: process.version,
|
|
563
|
+
});
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
### Tags vs Context vs Extra
|
|
567
|
+
|
|
568
|
+
| Feature | Searchable? | Indexed? | Best For |
|
|
569
|
+
| ----------- | ------------ | -------- | -------------------------------------- |
|
|
570
|
+
| **Tags** | ✅ Yes | ✅ Yes | Filtering, grouping, alerting |
|
|
571
|
+
| **Context** | ❌ No | ❌ No | Structured debug info (nested objects) |
|
|
572
|
+
| **Extra** | ❌ No | ❌ No | Arbitrary debug values |
|
|
573
|
+
| **User** | ✅ Partially | ✅ Yes | User attribution and filtering |
|
|
574
|
+
|
|
575
|
+
---
|
|
576
|
+
|
|
577
|
+
## Breadcrumbs
|
|
578
|
+
|
|
579
|
+
### Automatic Breadcrumbs (Zero Config)
|
|
580
|
+
|
|
581
|
+
| Type | What’s Captured |
|
|
582
|
+
| --------- | ------------------------------------------------- |
|
|
583
|
+
| `http` | Outgoing HTTP requests (URL, method, status code) |
|
|
584
|
+
| `console` | `console.log`, `warn`, `error` calls |
|
|
585
|
+
| `db` | Database queries (via OTel auto-instrumentation) |
|
|
586
|
+
|
|
587
|
+
### Manual Breadcrumbs
|
|
588
|
+
|
|
589
|
+
```javascript
|
|
590
|
+
Sentry.addBreadcrumb({
|
|
591
|
+
category: "auth",
|
|
592
|
+
message: `User ${user.email} authenticated`,
|
|
593
|
+
level: "info",
|
|
594
|
+
data: { method: "oauth2", provider: "google" },
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
Sentry.addBreadcrumb({
|
|
598
|
+
type: "http",
|
|
599
|
+
category: "http",
|
|
600
|
+
data: {
|
|
601
|
+
method: "POST",
|
|
602
|
+
url: "https://api.stripe.com/v1/charges",
|
|
603
|
+
status_code: 402,
|
|
604
|
+
},
|
|
605
|
+
level: "warning",
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
Sentry.addBreadcrumb({
|
|
609
|
+
type: "query",
|
|
610
|
+
category: "db.query",
|
|
611
|
+
message: "SELECT * FROM orders WHERE user_id = ?",
|
|
612
|
+
data: { db: "postgres", duration_ms: 42 },
|
|
613
|
+
});
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
### Breadcrumb Properties
|
|
617
|
+
|
|
618
|
+
| Key | Type | Values |
|
|
619
|
+
| ----------- | ------ | ------------------------------------------------------------------------------------------------------------------ |
|
|
620
|
+
| `type` | string | `"default"` \| `"debug"` \| `"error"` \| `"info"` \| `"http"` \| `"navigation"` \| `"query"` \| `"ui"` \| `"user"` |
|
|
621
|
+
| `category` | string | Dot-notation: `"auth"`, `"db.query"`, `"job.start"` |
|
|
622
|
+
| `message` | string | Human-readable description |
|
|
623
|
+
| `level` | string | `"fatal"` \| `"error"` \| `"warning"` \| `"log"` \| `"info"` \| `"debug"` |
|
|
624
|
+
| `timestamp` | number | Unix timestamp (auto-set if omitted) |
|
|
625
|
+
| `data` | object | Arbitrary key/value data |
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
## `beforeSend` and Filtering Hooks
|
|
630
|
+
|
|
631
|
+
### `beforeSend` — Modify or Drop Error Events
|
|
632
|
+
|
|
633
|
+
Last chance to modify or drop events.
|
|
634
|
+
Runs after all event processors.
|
|
635
|
+
Return `null` to drop.
|
|
636
|
+
**Only one `beforeSend` is allowed** — use `addEventProcessor` for multiple processors.
|
|
637
|
+
|
|
638
|
+
```javascript
|
|
639
|
+
Sentry.init({
|
|
640
|
+
beforeSend(event, hint) {
|
|
641
|
+
const err = hint.originalException;
|
|
642
|
+
|
|
643
|
+
// Drop in development
|
|
644
|
+
if (process.env.NODE_ENV === "development") return null;
|
|
645
|
+
|
|
646
|
+
// Drop specific error types
|
|
647
|
+
if (err instanceof ConnectionResetError) return null;
|
|
648
|
+
if (err?.message?.includes("ECONNRESET")) return null;
|
|
649
|
+
|
|
650
|
+
// Scrub PII from user object
|
|
651
|
+
if (event.user) {
|
|
652
|
+
delete event.user.email;
|
|
653
|
+
delete event.user.ip_address;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// Scrub sensitive keys from request body
|
|
657
|
+
if (event.request?.data) {
|
|
658
|
+
try {
|
|
659
|
+
const body = JSON.parse(event.request.data as string);
|
|
660
|
+
delete body.password;
|
|
661
|
+
delete body.token;
|
|
662
|
+
event.request.data = JSON.stringify(body);
|
|
663
|
+
} catch {}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// Custom fingerprint from error properties
|
|
667
|
+
if (err instanceof ApiError) {
|
|
668
|
+
event.fingerprint = ["api-error", String(err.statusCode), err.endpoint];
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// Filter noisy breadcrumbs
|
|
672
|
+
if (event.breadcrumbs?.values) {
|
|
673
|
+
event.breadcrumbs.values = event.breadcrumbs.values.filter(
|
|
674
|
+
(bc) => !bc.data?.url?.includes("/health")
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
return event;
|
|
679
|
+
},
|
|
680
|
+
|
|
681
|
+
// Drop specific transaction/span events
|
|
682
|
+
beforeSendTransaction(event) {
|
|
683
|
+
if (event.transaction === "GET /health") return null;
|
|
684
|
+
if (event.transaction === "GET /ping") return null;
|
|
685
|
+
return event;
|
|
686
|
+
},
|
|
687
|
+
});
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
### `beforeBreadcrumb` — Filter or Mutate Breadcrumbs
|
|
691
|
+
|
|
692
|
+
```javascript
|
|
693
|
+
Sentry.init({
|
|
694
|
+
beforeBreadcrumb(breadcrumb, hint) {
|
|
695
|
+
// Drop health-check HTTP requests
|
|
696
|
+
if (breadcrumb.type === "http" && breadcrumb.data?.url?.includes("/health")) {
|
|
697
|
+
return null;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// Redact auth tokens from URLs
|
|
701
|
+
if (breadcrumb.type === "http" && breadcrumb.data?.url) {
|
|
702
|
+
try {
|
|
703
|
+
const url = new URL(breadcrumb.data.url);
|
|
704
|
+
url.searchParams.delete("token");
|
|
705
|
+
url.searchParams.delete("api_key");
|
|
706
|
+
breadcrumb.data.url = url.toString();
|
|
707
|
+
} catch {}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
return breadcrumb;
|
|
711
|
+
},
|
|
712
|
+
maxBreadcrumbs: 50, // default: 100
|
|
713
|
+
});
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
### `ignoreErrors` — Pattern-Based Filtering
|
|
717
|
+
|
|
718
|
+
```javascript
|
|
719
|
+
Sentry.init({
|
|
720
|
+
ignoreErrors: ["Non-Error exception captured", /^ECONNRESET/, /^ETIMEDOUT/, /^socket hang up/],
|
|
721
|
+
ignoreTransactions: ["GET /health", "GET /ping", "GET /metrics", /^GET \/internal\//],
|
|
722
|
+
});
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
---
|
|
726
|
+
|
|
727
|
+
## Fingerprinting and Custom Grouping
|
|
728
|
+
|
|
729
|
+
All events have a `fingerprint` array.
|
|
730
|
+
Events with the same fingerprint group into the same Sentry issue.
|
|
731
|
+
|
|
732
|
+
### Per-Capture Fingerprinting
|
|
733
|
+
|
|
734
|
+
```javascript
|
|
735
|
+
Sentry.captureException(error, {
|
|
736
|
+
fingerprint: ["payment-declined", req.body.payment_method],
|
|
737
|
+
});
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
### `withScope` Fingerprinting
|
|
741
|
+
|
|
742
|
+
```javascript
|
|
743
|
+
Sentry.withScope((scope) => {
|
|
744
|
+
scope.setFingerprint([req.method, req.path, String(err.statusCode)]);
|
|
745
|
+
Sentry.captureException(err);
|
|
746
|
+
});
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
### `beforeSend` Fingerprinting (Global Rules)
|
|
750
|
+
|
|
751
|
+
```javascript
|
|
752
|
+
Sentry.init({
|
|
753
|
+
beforeSend(event, hint) {
|
|
754
|
+
const err = hint.originalException;
|
|
755
|
+
|
|
756
|
+
// All DB connection errors → one group
|
|
757
|
+
if (err instanceof DatabaseConnectionError) {
|
|
758
|
+
event.fingerprint = ["database-connection-error"];
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Group ApiErrors by status + endpoint
|
|
762
|
+
if (err instanceof ApiError) {
|
|
763
|
+
event.fingerprint = ["api-error", String(err.statusCode), err.endpoint];
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// Extend Sentry's default algorithm (keep stack-trace hash + add dimension)
|
|
767
|
+
if (err?.code) {
|
|
768
|
+
event.fingerprint = ["{{ default }}", err.code];
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
return event;
|
|
772
|
+
},
|
|
773
|
+
});
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
### Template Variables
|
|
777
|
+
|
|
778
|
+
| Variable | Description |
|
|
779
|
+
| ------------------- | ------------------------------------------------------------ |
|
|
780
|
+
| `{{ default }}` | Sentry’s normally computed hash — extend rather than replace |
|
|
781
|
+
| `{{ transaction }}` | Current transaction name |
|
|
782
|
+
| `{{ function }}` | Top function in stack trace |
|
|
783
|
+
| `{{ type }}` | Exception type name |
|
|
784
|
+
|
|
785
|
+
---
|
|
786
|
+
|
|
787
|
+
## Event Processors
|
|
788
|
+
|
|
789
|
+
Unlike `beforeSend` (one allowed), multiple event processors can be registered.
|
|
790
|
+
Order is not guaranteed.
|
|
791
|
+
`beforeSend` always runs last.
|
|
792
|
+
|
|
793
|
+
```javascript
|
|
794
|
+
// Runs on every event — enrich with deploy metadata
|
|
795
|
+
Sentry.addEventProcessor((event, hint) => {
|
|
796
|
+
event.tags = {
|
|
797
|
+
...event.tags,
|
|
798
|
+
git_sha: process.env.GIT_SHA ?? "unknown",
|
|
799
|
+
deployed_by: process.env.DEPLOY_USER ?? "unknown",
|
|
800
|
+
};
|
|
801
|
+
return event;
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
// Drop events with a custom ignore flag
|
|
805
|
+
Sentry.addEventProcessor((event, hint) => {
|
|
806
|
+
if ((hint.originalException as any)?.ignore_in_sentry === true) return null;
|
|
807
|
+
return event;
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
// Scope-level processor (only inside withScope callback)
|
|
811
|
+
Sentry.withScope((scope) => {
|
|
812
|
+
scope.addEventProcessor((event) => {
|
|
813
|
+
event.tags = { ...event.tags, batch_job: "true" };
|
|
814
|
+
return event;
|
|
815
|
+
});
|
|
816
|
+
Sentry.captureException(new Error("job failed"));
|
|
817
|
+
});
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
**`addEventProcessor` vs `beforeSend`:**
|
|
821
|
+
|
|
822
|
+
| | `addEventProcessor` | `beforeSend` |
|
|
823
|
+
| ----------- | ------------------------------- | ------------- |
|
|
824
|
+
| Count | Unlimited | One only |
|
|
825
|
+
| Order | Undefined (before `beforeSend`) | Always last |
|
|
826
|
+
| Async | ✅ Yes | ✅ Yes |
|
|
827
|
+
| Drop events | Return `null` | Return `null` |
|
|
828
|
+
|
|
829
|
+
---
|
|
830
|
+
|
|
831
|
+
## `requestDataIntegration` — Per-Request Data
|
|
832
|
+
|
|
833
|
+
Auto-enabled. Attaches HTTP request data to all events during a request.
|
|
834
|
+
Each framework auto-forks an isolation scope per request via OpenTelemetry
|
|
835
|
+
`AsyncLocalStorage` — concurrent requests stay separate.
|
|
836
|
+
|
|
837
|
+
| Field | Captured | Notes |
|
|
838
|
+
| -------------- | ------------- | ---------------------------------------------------------------------- |
|
|
839
|
+
| `url` | ✅ Always | Full request URL |
|
|
840
|
+
| `method` | ✅ Always | GET, POST, etc. |
|
|
841
|
+
| `headers` | ✅ Always | Auth header scrubbed automatically |
|
|
842
|
+
| `query_string` | ✅ Always | URL query params |
|
|
843
|
+
| `data` (body) | ✅ Default on | Controlled by `dataCollection` (`httpBodies`); set to `[]` to opt out |
|
|
844
|
+
| `cookies` | ✅ Default on | Controlled by `dataCollection` (`cookies`); set to `false` to opt out |
|
|
845
|
+
| `ip_address` | ✅ Default on | Controlled by `dataCollection` (`userInfo`); set to `false` to opt out |
|
|
846
|
+
|
|
847
|
+
```javascript
|
|
848
|
+
Sentry.init({
|
|
849
|
+
dataCollection: {
|
|
850
|
+
// To disable sending user data and HTTP bodies, uncomment the lines below. For more info visit:
|
|
851
|
+
// https://docs.sentry.io/platforms/javascript/guides/node/configuration/options/#dataCollection
|
|
852
|
+
// userInfo: false,
|
|
853
|
+
// httpBodies: [],
|
|
854
|
+
},
|
|
855
|
+
integrations: [
|
|
856
|
+
Sentry.requestDataIntegration({
|
|
857
|
+
include: {
|
|
858
|
+
cookies: true,
|
|
859
|
+
data: true, // request body
|
|
860
|
+
headers: true,
|
|
861
|
+
ip: true,
|
|
862
|
+
query_string: true,
|
|
863
|
+
url: true,
|
|
864
|
+
user: { id: true, username: true, email: false },
|
|
865
|
+
},
|
|
866
|
+
}),
|
|
867
|
+
],
|
|
868
|
+
});
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
---
|
|
872
|
+
|
|
873
|
+
## Error Chains
|
|
874
|
+
|
|
875
|
+
`linkedErrorsIntegration` is auto-enabled and follows the standard `Error.cause` chain.
|
|
876
|
+
|
|
877
|
+
```javascript
|
|
878
|
+
// Standard Error.cause — captured automatically
|
|
879
|
+
try {
|
|
880
|
+
await connectToDatabase();
|
|
881
|
+
} catch (dbError) {
|
|
882
|
+
throw new Error("Failed to process order", { cause: dbError });
|
|
883
|
+
// Sentry captures BOTH errors as a chain
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// Configure depth (default: 5)
|
|
887
|
+
Sentry.init({
|
|
888
|
+
integrations: [Sentry.linkedErrorsIntegration({ key: "cause", limit: 5 })],
|
|
889
|
+
});
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
### `extraErrorDataIntegration` — Custom Error Properties
|
|
893
|
+
|
|
894
|
+
Captures non-standard properties on Error subclasses:
|
|
895
|
+
|
|
896
|
+
```javascript
|
|
897
|
+
Sentry.init({
|
|
898
|
+
integrations: [Sentry.extraErrorDataIntegration({ depth: 3 })],
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
class HttpError extends Error {
|
|
902
|
+
constructor(message, response) {
|
|
903
|
+
super(message);
|
|
904
|
+
this.statusCode = response.status; // captured in extras
|
|
905
|
+
this.responseBody = response.body; // captured in extras
|
|
906
|
+
this.endpoint = response.url; // captured in extras
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
---
|
|
912
|
+
|
|
913
|
+
## Lifecycle: Flush Before Shutdown
|
|
914
|
+
|
|
915
|
+
`@sentry/node` batches events and sends asynchronously.
|
|
916
|
+
Always flush before process exit to avoid losing the last events.
|
|
917
|
+
|
|
918
|
+
```javascript
|
|
919
|
+
// Graceful shutdown — HTTP server
|
|
920
|
+
process.on("SIGTERM", async () => {
|
|
921
|
+
server.close(async () => {
|
|
922
|
+
await Sentry.flush(2000); // wait up to 2s for queue to drain
|
|
923
|
+
process.exit(0);
|
|
924
|
+
});
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
// Serverless (Lambda, Cloud Functions) — close disables SDK after flush
|
|
928
|
+
export const handler = async (event) => {
|
|
929
|
+
try {
|
|
930
|
+
return await processEvent(event);
|
|
931
|
+
} catch (err) {
|
|
932
|
+
Sentry.captureException(err);
|
|
933
|
+
await Sentry.close(2000); // flush + disable before function freezes
|
|
934
|
+
throw err;
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
---
|
|
940
|
+
|
|
941
|
+
## `Sentry.init()` — Error-Relevant Options
|
|
942
|
+
|
|
943
|
+
```typescript
|
|
944
|
+
Sentry.init({
|
|
945
|
+
// Identity
|
|
946
|
+
dsn?: string; // also: SENTRY_DSN env var
|
|
947
|
+
release?: string; // "my-app@1.2.3+abc123"
|
|
948
|
+
environment?: string; // default: "production"
|
|
949
|
+
serverName?: string; // hostname
|
|
950
|
+
enabled?: boolean; // default: true
|
|
951
|
+
|
|
952
|
+
// Sampling
|
|
953
|
+
sampleRate?: number; // 0.0–1.0 error event sample rate
|
|
954
|
+
tracesSampleRate?: number; // 0.0–1.0 transaction sample rate
|
|
955
|
+
|
|
956
|
+
// Data limits
|
|
957
|
+
maxBreadcrumbs?: number; // default: 100
|
|
958
|
+
maxValueLength?: number; // truncate long strings
|
|
959
|
+
normalizeDepth?: number; // default: 3
|
|
960
|
+
|
|
961
|
+
// Privacy
|
|
962
|
+
dataCollection?: DataCollectionOptions; // omitted => falls back to sendDefaultPii (conservative); pass an object (even {}) to enable permissive collection, then opt out per category
|
|
963
|
+
|
|
964
|
+
// Filtering
|
|
965
|
+
ignoreErrors?: Array<string | RegExp>;
|
|
966
|
+
ignoreTransactions?: Array<string | RegExp>;
|
|
967
|
+
|
|
968
|
+
// Hooks
|
|
969
|
+
beforeSend?: (event: Event, hint: EventHint) => Event | null;
|
|
970
|
+
beforeSendTransaction?: (event: Event, hint: EventHint) => Event | null;
|
|
971
|
+
beforeBreadcrumb?: (breadcrumb: Breadcrumb, hint?: BreadcrumbHint) => Breadcrumb | null;
|
|
972
|
+
|
|
973
|
+
// Node-specific
|
|
974
|
+
enableLogs?: boolean; // default: false — Sentry.logger.*
|
|
975
|
+
attachStacktrace?: boolean; // add stack traces to captureMessage
|
|
976
|
+
includeLocalVariables?: boolean; // include local vars in stack frames
|
|
977
|
+
onFatalError?: (error: Error) => void;
|
|
978
|
+
shutdownTimeout?: number; // default: 2000ms
|
|
979
|
+
});
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
---
|
|
983
|
+
|
|
984
|
+
## Bun
|
|
985
|
+
|
|
986
|
+
`@sentry/bun` is a thin wrapper over `@sentry/node`. The API is identical — use
|
|
987
|
+
`--preload` instead of `require("./instrument")` first.
|
|
988
|
+
|
|
989
|
+
```typescript
|
|
990
|
+
// instrument.ts
|
|
991
|
+
import * as Sentry from "@sentry/bun";
|
|
992
|
+
|
|
993
|
+
Sentry.init({
|
|
994
|
+
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
995
|
+
tracesSampleRate: 1.0,
|
|
996
|
+
dataCollection: {
|
|
997
|
+
// To disable sending user data and HTTP bodies, uncomment the lines below. For more info visit:
|
|
998
|
+
// https://docs.sentry.io/platforms/javascript/guides/node/configuration/options/#dataCollection
|
|
999
|
+
// userInfo: false,
|
|
1000
|
+
// httpBodies: [],
|
|
1001
|
+
},
|
|
1002
|
+
});
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
```bash
|
|
1006
|
+
bun --preload ./instrument.ts server.ts
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1009
|
+
For `Bun.serve()`:
|
|
1010
|
+
|
|
1011
|
+
```typescript
|
|
1012
|
+
import * as Sentry from "@sentry/bun";
|
|
1013
|
+
|
|
1014
|
+
const server = Bun.serve({
|
|
1015
|
+
port: 3000,
|
|
1016
|
+
fetch(request) {
|
|
1017
|
+
return new Response("Hello from Bun!");
|
|
1018
|
+
},
|
|
1019
|
+
error(error) {
|
|
1020
|
+
Sentry.captureException(error); // manual — no setupErrorHandler for Bun.serve
|
|
1021
|
+
return new Response("Internal Server Error", { status: 500 });
|
|
1022
|
+
},
|
|
1023
|
+
});
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
> **Profiling:** `@sentry/profiling-node` uses a native addon — incompatible with Bun’s
|
|
1027
|
+
> runtime. Omit `nodeProfilingIntegration()` in Bun apps.
|
|
1028
|
+
|
|
1029
|
+
---
|
|
1030
|
+
|
|
1031
|
+
## Deno
|
|
1032
|
+
|
|
1033
|
+
```typescript
|
|
1034
|
+
// instrument.ts
|
|
1035
|
+
import * as Sentry from "npm:@sentry/deno";
|
|
1036
|
+
|
|
1037
|
+
Sentry.init({
|
|
1038
|
+
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
1039
|
+
tracesSampleRate: 1.0,
|
|
1040
|
+
});
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
```typescript
|
|
1044
|
+
// server.ts
|
|
1045
|
+
import "../instrument.ts";
|
|
1046
|
+
import * as Sentry from "npm:@sentry/deno";
|
|
1047
|
+
|
|
1048
|
+
Deno.serve({ port: 3000 }, async (request) => {
|
|
1049
|
+
try {
|
|
1050
|
+
return new Response("Hello from Deno!");
|
|
1051
|
+
} catch (error) {
|
|
1052
|
+
Sentry.captureException(error);
|
|
1053
|
+
return new Response("Internal Server Error", { status: 500 });
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
> **Requirements:** Deno 2+. Run with `--allow-net --allow-env --allow-read`. No
|
|
1059
|
+
> `setupExpressErrorHandler` equivalent — use `try/catch` + `captureException`.
|
|
1060
|
+
|
|
1061
|
+
---
|
|
1062
|
+
|
|
1063
|
+
## Quick Reference
|
|
1064
|
+
|
|
1065
|
+
```javascript
|
|
1066
|
+
// Init
|
|
1067
|
+
Sentry.init({ dsn: "...", tracesSampleRate: 1.0 });
|
|
1068
|
+
|
|
1069
|
+
// Capture
|
|
1070
|
+
Sentry.captureException(new Error("oops"));
|
|
1071
|
+
Sentry.captureException(err, { tags: { source: "api" }, level: "fatal" });
|
|
1072
|
+
Sentry.captureMessage("Something happened", "warning");
|
|
1073
|
+
|
|
1074
|
+
// Context (→ isolation scope, auto-forked per request)
|
|
1075
|
+
Sentry.setUser({ id: 1, email: "user@example.com" });
|
|
1076
|
+
Sentry.setTag("region", "us-east");
|
|
1077
|
+
Sentry.setTags({ service: "checkout", version: "2.0" });
|
|
1078
|
+
Sentry.setContext("cart", { items: 3, total: 49.99 });
|
|
1079
|
+
Sentry.addBreadcrumb({ category: "auth", message: "login", level: "info" });
|
|
1080
|
+
|
|
1081
|
+
// Scoped capture (temporary context, one event only)
|
|
1082
|
+
Sentry.withScope((scope) => {
|
|
1083
|
+
scope.setTag("temp_tag", "only-this-event");
|
|
1084
|
+
scope.setFingerprint(["my-custom-group"]);
|
|
1085
|
+
scope.setLevel("warning");
|
|
1086
|
+
Sentry.captureException(err);
|
|
1087
|
+
});
|
|
1088
|
+
|
|
1089
|
+
// Background job isolation
|
|
1090
|
+
await Sentry.withIsolationScope(async (scope) => {
|
|
1091
|
+
scope.setUser({ id: job.userId });
|
|
1092
|
+
await processJob(job);
|
|
1093
|
+
});
|
|
1094
|
+
|
|
1095
|
+
// Global (all events, process lifetime)
|
|
1096
|
+
Sentry.getGlobalScope().setTag("app", "my-api");
|
|
1097
|
+
|
|
1098
|
+
// Framework error handlers — placement matters!
|
|
1099
|
+
Sentry.setupExpressErrorHandler(app); // Express: AFTER routes
|
|
1100
|
+
Sentry.setupFastifyErrorHandler(app); // Fastify: BEFORE routes
|
|
1101
|
+
Sentry.setupKoaErrorHandler(app); // Koa: FIRST middleware
|
|
1102
|
+
await Sentry.setupHapiErrorHandler(server); // Hapi: BEFORE routes, MUST await
|
|
1103
|
+
Sentry.setupConnectErrorHandler(app); // Connect: BEFORE routes
|
|
1104
|
+
|
|
1105
|
+
// Shutdown
|
|
1106
|
+
await Sentry.flush(2000);
|
|
1107
|
+
```
|
|
1108
|
+
|
|
1109
|
+
---
|
|
1110
|
+
|
|
1111
|
+
## Troubleshooting
|
|
1112
|
+
|
|
1113
|
+
| Issue | Cause | Solution |
|
|
1114
|
+
| ----------------------------------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
1115
|
+
| Errors not appearing in Sentry | `instrument.js` loaded too late | Ensure it’s the first `require()` or loaded via `--import` / `--preload` before app code |
|
|
1116
|
+
| Express errors not captured | `setupExpressErrorHandler` placed before routes | Move it **after** all route definitions |
|
|
1117
|
+
| Fastify errors not captured | `setupFastifyErrorHandler` placed after routes | Move it **before** route definitions (opposite of Express) |
|
|
1118
|
+
| Hapi error handler silently fails | `setupHapiErrorHandler` not awaited | Must `await Sentry.setupHapiErrorHandler(server)` — it’s the only async handler |
|
|
1119
|
+
| NestJS `HttpException` not captured | Intentional — `SentryGlobalFilter` skips control flow exceptions | Create a custom filter extending `SentryGlobalFilter` and override `catch()` to capture `HttpException` if desired |
|
|
1120
|
+
| `setUser()` leaks between requests | Using global scope for user data | Use `Sentry.setUser()` (isolation scope) — it’s auto-forked per request by framework integrations |
|
|
1121
|
+
| `withScope` changes persisting | Wrong scope layer | `withScope` creates a temporary current scope — changes don’t survive the callback. Use `setTag()` for request-lifetime data |
|
|
1122
|
+
| `beforeSend` returning wrong type | Not returning `event` or `null` | `beforeSend` must return the event object or `null` to drop — `undefined` causes silent failures |
|
|
1123
|
+
| Breadcrumbs not showing | `maxBreadcrumbs: 0` | Check init config — default is 100; set to desired max |
|
|
1124
|
+
| Duplicate error events | Multiple capture paths | Ensure only one handler captures each error — e.g., don’t both re-throw and call `captureException` |
|
|
1125
|
+
| Stack traces show minified code | Source maps not uploaded | Configure `@sentry/cli` sourcemap upload in your build pipeline |
|