@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,1100 @@
|
|
|
1
|
+
# Error Monitoring — Sentry .NET SDK
|
|
2
|
+
|
|
3
|
+
> Minimum SDK: `Sentry` ≥ 4.0.0 (NuGet)\
|
|
4
|
+
> ASP.NET Core integration: `Sentry.AspNetCore` ≥ 4.0.0\
|
|
5
|
+
> MAUI integration: `Sentry.Maui` ≥ 4.0.0\
|
|
6
|
+
> User feedback API: `Sentry` ≥ 4.0.0 (`CaptureFeedback`)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Automatic vs Manual Error Capture
|
|
11
|
+
|
|
12
|
+
### What Is Captured Automatically
|
|
13
|
+
|
|
14
|
+
| Error Type | Captured? | Mechanism |
|
|
15
|
+
| ------------------------------------ | --------- | ------------------------------------------------------ |
|
|
16
|
+
| Unhandled exceptions (all platforms) | ✅ Yes | `AppDomain.CurrentDomain.UnhandledException` |
|
|
17
|
+
| Unobserved Task exceptions | ✅ Yes | `TaskScheduler.UnobservedTaskException` |
|
|
18
|
+
| ASP.NET Core request errors | ✅ Yes | Sentry middleware |
|
|
19
|
+
| WPF Dispatcher unhandled exceptions | ✅ Yes | `Application.DispatcherUnhandledException` (with hook) |
|
|
20
|
+
| MAUI unhandled exceptions | ✅ Yes | Platform-specific native integrations |
|
|
21
|
+
| WinForms exceptions | ✅ Yes | Requires `SetUnhandledExceptionMode(ThrowException)` |
|
|
22
|
+
| Caught + swallowed `try/catch` | ❌ No | Must call `SentrySdk.CaptureException()` manually |
|
|
23
|
+
| Graceful error returns | ❌ No | Must call `SentrySdk.CaptureException()` manually |
|
|
24
|
+
|
|
25
|
+
### The Core Rule
|
|
26
|
+
|
|
27
|
+
> **“If you catch an exception and don’t re-throw it, Sentry never sees it.”**
|
|
28
|
+
|
|
29
|
+
```csharp
|
|
30
|
+
// ✅ Automatically captured — unhandled, bubbles up
|
|
31
|
+
throw new Exception("Unhandled");
|
|
32
|
+
|
|
33
|
+
// ✅ Automatically captured — re-thrown
|
|
34
|
+
try
|
|
35
|
+
{
|
|
36
|
+
await DoSomethingAsync();
|
|
37
|
+
}
|
|
38
|
+
catch (Exception ex)
|
|
39
|
+
{
|
|
40
|
+
throw; // re-throw preserves stack trace
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ❌ NOT captured — swallowed by graceful return
|
|
44
|
+
try
|
|
45
|
+
{
|
|
46
|
+
await DoSomethingAsync();
|
|
47
|
+
}
|
|
48
|
+
catch (Exception ex)
|
|
49
|
+
{
|
|
50
|
+
return Result.Failure("Operation failed"); // ← Sentry never sees this
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ✅ Manually captured
|
|
54
|
+
try
|
|
55
|
+
{
|
|
56
|
+
await DoSomethingAsync();
|
|
57
|
+
}
|
|
58
|
+
catch (Exception ex)
|
|
59
|
+
{
|
|
60
|
+
SentrySdk.CaptureException(ex);
|
|
61
|
+
return Result.Failure("Operation failed");
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Core Capture API
|
|
68
|
+
|
|
69
|
+
### `SentrySdk.CaptureException`
|
|
70
|
+
|
|
71
|
+
```csharp
|
|
72
|
+
// Basic — capture a caught exception
|
|
73
|
+
SentryId id = SentrySdk.CaptureException(exception);
|
|
74
|
+
|
|
75
|
+
// With inline scope enrichment — changes are isolated to this ONE event
|
|
76
|
+
SentryId id = SentrySdk.CaptureException(exception, scope =>
|
|
77
|
+
{
|
|
78
|
+
scope.SetTag("order.id", orderId.ToString());
|
|
79
|
+
scope.Level = SentryLevel.Fatal;
|
|
80
|
+
scope.User = new SentryUser { Id = userId };
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
> **Key behavior:** The SDK clones the current scope before invoking the callback.
|
|
85
|
+
> Changes inside the callback apply only to that one event and do not affect subsequent
|
|
86
|
+
> events.
|
|
87
|
+
|
|
88
|
+
### `SentrySdk.CaptureMessage`
|
|
89
|
+
|
|
90
|
+
```csharp
|
|
91
|
+
// Default level is Info
|
|
92
|
+
SentrySdk.CaptureMessage("Something notable happened");
|
|
93
|
+
|
|
94
|
+
// With explicit severity
|
|
95
|
+
SentrySdk.CaptureMessage("Disk space critically low", SentryLevel.Warning);
|
|
96
|
+
|
|
97
|
+
// With scope enrichment
|
|
98
|
+
SentrySdk.CaptureMessage("Payment gateway timeout", scope =>
|
|
99
|
+
{
|
|
100
|
+
scope.SetTag("gateway", "stripe");
|
|
101
|
+
scope.Level = SentryLevel.Error;
|
|
102
|
+
}, SentryLevel.Error);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**SentryLevel values:**
|
|
106
|
+
|
|
107
|
+
```csharp
|
|
108
|
+
SentryLevel.Debug
|
|
109
|
+
SentryLevel.Info // default for CaptureMessage
|
|
110
|
+
SentryLevel.Warning
|
|
111
|
+
SentryLevel.Error
|
|
112
|
+
SentryLevel.Fatal
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `SentrySdk.CaptureEvent`
|
|
116
|
+
|
|
117
|
+
For full manual control over every field on the event:
|
|
118
|
+
|
|
119
|
+
```csharp
|
|
120
|
+
var evt = new SentryEvent
|
|
121
|
+
{
|
|
122
|
+
Message = new SentryMessage { Message = "Custom structured event" },
|
|
123
|
+
Level = SentryLevel.Error
|
|
124
|
+
};
|
|
125
|
+
evt.SetTag("custom-tag", "value");
|
|
126
|
+
evt.Fingerprint = new[] { "custom-fingerprint" };
|
|
127
|
+
SentrySdk.CaptureEvent(evt);
|
|
128
|
+
|
|
129
|
+
// Construct from a caught exception
|
|
130
|
+
try { ... }
|
|
131
|
+
catch (Exception ex)
|
|
132
|
+
{
|
|
133
|
+
var evt = new SentryEvent(ex)
|
|
134
|
+
{
|
|
135
|
+
Level = SentryLevel.Fatal
|
|
136
|
+
};
|
|
137
|
+
SentrySdk.CaptureEvent(evt);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### All capture signatures
|
|
142
|
+
|
|
143
|
+
```csharp
|
|
144
|
+
// CaptureException
|
|
145
|
+
SentryId SentrySdk.CaptureException(Exception exception)
|
|
146
|
+
SentryId SentrySdk.CaptureException(Exception exception, Action<Scope> configureScope)
|
|
147
|
+
|
|
148
|
+
// CaptureMessage
|
|
149
|
+
SentryId SentrySdk.CaptureMessage(string message, SentryLevel level = SentryLevel.Info)
|
|
150
|
+
SentryId SentrySdk.CaptureMessage(string message, Action<Scope> configureScope,
|
|
151
|
+
SentryLevel level = SentryLevel.Info)
|
|
152
|
+
|
|
153
|
+
// CaptureEvent
|
|
154
|
+
SentryId SentrySdk.CaptureEvent(SentryEvent evt, Scope? scope = null, SentryHint? hint = null)
|
|
155
|
+
SentryId SentrySdk.CaptureEvent(SentryEvent evt, Action<Scope> configureScope)
|
|
156
|
+
SentryId SentrySdk.CaptureEvent(SentryEvent evt, SentryHint? hint, Action<Scope> configureScope)
|
|
157
|
+
|
|
158
|
+
// Flush
|
|
159
|
+
void SentrySdk.Flush()
|
|
160
|
+
void SentrySdk.Flush(TimeSpan timeout)
|
|
161
|
+
Task SentrySdk.FlushAsync(TimeSpan timeout)
|
|
162
|
+
|
|
163
|
+
// Utility
|
|
164
|
+
bool SentrySdk.IsEnabled
|
|
165
|
+
SentryId SentrySdk.LastEventId
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## ASP.NET Core — Automatic & Manual Error Capture
|
|
171
|
+
|
|
172
|
+
### Installation
|
|
173
|
+
|
|
174
|
+
```shell
|
|
175
|
+
dotnet add package Sentry.AspNetCore
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Initialization in `Program.cs`
|
|
179
|
+
|
|
180
|
+
```csharp
|
|
181
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
182
|
+
|
|
183
|
+
builder.WebHost.UseSentry(options =>
|
|
184
|
+
{
|
|
185
|
+
options.Dsn = "https://...@sentry.io/...";
|
|
186
|
+
options.SendDefaultPii = true; // Include user IP, headers, auth
|
|
187
|
+
options.MaxRequestBodySize = RequestSize.Always;
|
|
188
|
+
options.TracesSampleRate = 1.0;
|
|
189
|
+
options.Debug = true;
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
var app = builder.Build();
|
|
193
|
+
app.Run();
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Via `appsettings.json` (no code required)
|
|
197
|
+
|
|
198
|
+
```json
|
|
199
|
+
{
|
|
200
|
+
"Sentry": {
|
|
201
|
+
"Dsn": "https://...@sentry.io/...",
|
|
202
|
+
"SendDefaultPii": true,
|
|
203
|
+
"MaxRequestBodySize": "Always",
|
|
204
|
+
"MinimumBreadcrumbLevel": "Debug",
|
|
205
|
+
"MinimumEventLevel": "Warning",
|
|
206
|
+
"AttachStacktrace": true,
|
|
207
|
+
"Debug": true,
|
|
208
|
+
"TracesSampleRate": 1.0
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Via environment variables (double-underscore convention)
|
|
214
|
+
|
|
215
|
+
```shell
|
|
216
|
+
Sentry__Dsn=https://...@sentry.io/...
|
|
217
|
+
Sentry__Debug=true
|
|
218
|
+
Sentry__TracesSampleRate=0.5
|
|
219
|
+
Sentry__SendDefaultPii=true
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### What ASP.NET Core captures automatically
|
|
223
|
+
|
|
224
|
+
- All unhandled exceptions thrown from controllers and middleware → captured as Sentry
|
|
225
|
+
events
|
|
226
|
+
- HTTP request data (URL, method, headers, body if configured)
|
|
227
|
+
- User info from `IHttpContext` when `SendDefaultPii = true`
|
|
228
|
+
- Breadcrumbs and Events from `Microsoft.Extensions.Logging`
|
|
229
|
+
- Performance transactions for each HTTP request (when `TracesSampleRate > 0`)
|
|
230
|
+
|
|
231
|
+
### Manual capture in a controller
|
|
232
|
+
|
|
233
|
+
```csharp
|
|
234
|
+
[ApiController]
|
|
235
|
+
[Route("[controller]")]
|
|
236
|
+
public class OrderController : ControllerBase
|
|
237
|
+
{
|
|
238
|
+
[HttpPost]
|
|
239
|
+
public IActionResult CreateOrder(OrderRequest request)
|
|
240
|
+
{
|
|
241
|
+
try
|
|
242
|
+
{
|
|
243
|
+
_orderService.Create(request);
|
|
244
|
+
return Ok();
|
|
245
|
+
}
|
|
246
|
+
catch (PaymentDeclinedException ex)
|
|
247
|
+
{
|
|
248
|
+
SentrySdk.CaptureException(ex, scope =>
|
|
249
|
+
{
|
|
250
|
+
scope.SetTag("payment.gateway", request.PaymentGateway);
|
|
251
|
+
scope.SetExtra("order_amount", request.Amount);
|
|
252
|
+
});
|
|
253
|
+
return StatusCode(402, "Payment declined");
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Custom user factory (DI)
|
|
260
|
+
|
|
261
|
+
```csharp
|
|
262
|
+
public class MyUserFactory : ISentryUserFactory
|
|
263
|
+
{
|
|
264
|
+
private readonly IHttpContextAccessor _accessor;
|
|
265
|
+
|
|
266
|
+
public MyUserFactory(IHttpContextAccessor accessor)
|
|
267
|
+
=> _accessor = accessor;
|
|
268
|
+
|
|
269
|
+
public SentryUser? Create()
|
|
270
|
+
{
|
|
271
|
+
var user = _accessor.HttpContext?.User;
|
|
272
|
+
if (user?.Identity?.IsAuthenticated != true) return null;
|
|
273
|
+
|
|
274
|
+
return new SentryUser
|
|
275
|
+
{
|
|
276
|
+
Id = user.FindFirst(ClaimTypes.NameIdentifier)?.Value,
|
|
277
|
+
Email = user.FindFirst(ClaimTypes.Email)?.Value,
|
|
278
|
+
Username = user.Identity.Name
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Register in DI
|
|
284
|
+
services.AddSingleton<ISentryUserFactory, MyUserFactory>();
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### ASP.NET Core-specific options
|
|
288
|
+
|
|
289
|
+
| Option | Type | Description |
|
|
290
|
+
| ------------------------ | ------------- | ----------------------------------------------------------- |
|
|
291
|
+
| `SendDefaultPii` | `bool` | Include request URL, headers, user IP, auth info |
|
|
292
|
+
| `MaxRequestBodySize` | `RequestSize` | `None`, `Small` (<4 KB), `Medium` (<10 KB), `Always` |
|
|
293
|
+
| `MinimumBreadcrumbLevel` | `LogLevel` | Min log level for breadcrumb capture from ILogger |
|
|
294
|
+
| `MinimumEventLevel` | `LogLevel` | Min log level to generate a Sentry error event from ILogger |
|
|
295
|
+
| `CaptureBlockingCalls` | `bool` | Detect `Task.Wait()` / `.Result` threadpool starvation |
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Scope Management
|
|
300
|
+
|
|
301
|
+
### How Scopes Work in .NET
|
|
302
|
+
|
|
303
|
+
The **Hub** holds a stack of scopes.
|
|
304
|
+
When an event is captured the hub merges the topmost scope’s data into the event.
|
|
305
|
+
Scope storage mode is controlled by `IsGlobalModeEnabled`:
|
|
306
|
+
|
|
307
|
+
| `IsGlobalModeEnabled` | Storage | Use For |
|
|
308
|
+
| --------------------- | --------------- | ------------------------------------------ |
|
|
309
|
+
| `false` (default) | `AsyncLocal<T>` | Server apps — per-request isolation |
|
|
310
|
+
| `true` | Singleton | Desktop apps — shared scope across threads |
|
|
311
|
+
|
|
312
|
+
### `ConfigureScope` — Persistent Changes
|
|
313
|
+
|
|
314
|
+
Modifies the current ambient scope permanently (until changed or scope is popped).
|
|
315
|
+
Use for session-level data:
|
|
316
|
+
|
|
317
|
+
```csharp
|
|
318
|
+
SentrySdk.ConfigureScope(scope =>
|
|
319
|
+
{
|
|
320
|
+
scope.SetTag("tenant.id", tenantId);
|
|
321
|
+
scope.User = new SentryUser
|
|
322
|
+
{
|
|
323
|
+
Id = user.Id.ToString(),
|
|
324
|
+
Email = user.Email
|
|
325
|
+
};
|
|
326
|
+
scope.Level = SentryLevel.Warning;
|
|
327
|
+
scope.TransactionName = "UserCheckout";
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// Async variant
|
|
331
|
+
await SentrySdk.ConfigureScopeAsync(async scope =>
|
|
332
|
+
{
|
|
333
|
+
var user = await _context.Users.FindAsync(userId);
|
|
334
|
+
scope.User = new SentryUser { Id = user.Id.ToString(), Email = user.Email };
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Allocation-free overload (avoids closure)
|
|
338
|
+
SentrySdk.ConfigureScope(
|
|
339
|
+
static (scope, tenantId) => scope.SetTag("tenant.id", tenantId),
|
|
340
|
+
currentTenantId);
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### `PushScope` — Temporary Isolated Scope
|
|
344
|
+
|
|
345
|
+
Inherits parent scope data.
|
|
346
|
+
All changes inside the `using` block are discarded when disposed:
|
|
347
|
+
|
|
348
|
+
```csharp
|
|
349
|
+
using (SentrySdk.PushScope())
|
|
350
|
+
{
|
|
351
|
+
SentrySdk.ConfigureScope(scope =>
|
|
352
|
+
{
|
|
353
|
+
scope.SetTag("operation", "bulk-import");
|
|
354
|
+
scope.User = new SentryUser { Id = userId };
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
SentrySdk.CaptureException(new Exception("Scoped error"));
|
|
358
|
+
} // scope is popped here — tags/user cleared
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Inline scope callback (preferred for single events)
|
|
362
|
+
|
|
363
|
+
The `configureScope` callback on capture methods is the preferred pattern for one-off
|
|
364
|
+
enrichment without needing a `using` block:
|
|
365
|
+
|
|
366
|
+
```csharp
|
|
367
|
+
// Only this event carries the tag
|
|
368
|
+
SentrySdk.CaptureException(ex, scope =>
|
|
369
|
+
{
|
|
370
|
+
scope.SetTag("action", "checkout");
|
|
371
|
+
scope.Level = SentryLevel.Fatal;
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// The next event is NOT affected
|
|
375
|
+
SentrySdk.CaptureException(otherEx);
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Clearing scope data
|
|
379
|
+
|
|
380
|
+
```csharp
|
|
381
|
+
SentrySdk.ConfigureScope(scope =>
|
|
382
|
+
{
|
|
383
|
+
scope.User = new SentryUser(); // Clear user (e.g., on logout)
|
|
384
|
+
scope.Clear(); // Clear everything
|
|
385
|
+
scope.ClearBreadcrumbs();
|
|
386
|
+
scope.ClearAttachments();
|
|
387
|
+
});
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Scope decision guide
|
|
391
|
+
|
|
392
|
+
| Goal | API |
|
|
393
|
+
| ------------------------------------------ | ------------------------------------------- |
|
|
394
|
+
| Data on ALL events (app version, build ID) | `options.DefaultTags["key"] = "value"` |
|
|
395
|
+
| Session/request-level data | `SentrySdk.ConfigureScope(...)` |
|
|
396
|
+
| One specific event only | Inline `configureScope` callback on capture |
|
|
397
|
+
| Temporary sub-context (batch job, etc.) | `SentrySdk.PushScope()` + `using` |
|
|
398
|
+
|
|
399
|
+
---
|
|
400
|
+
|
|
401
|
+
## Context Enrichment
|
|
402
|
+
|
|
403
|
+
### Tags (Indexed, Searchable)
|
|
404
|
+
|
|
405
|
+
Tags are **indexed** — use them for filtering, grouping, and alerting rules.
|
|
406
|
+
|
|
407
|
+
```csharp
|
|
408
|
+
SentrySdk.ConfigureScope(scope =>
|
|
409
|
+
{
|
|
410
|
+
scope.SetTag("page.locale", "de-at");
|
|
411
|
+
scope.SetTag("user.plan", "enterprise");
|
|
412
|
+
|
|
413
|
+
// Set multiple at once
|
|
414
|
+
scope.SetTags(new Dictionary<string, string>
|
|
415
|
+
{
|
|
416
|
+
["environment"] = "staging",
|
|
417
|
+
["region"] = "us-east-1"
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
// Unset a tag
|
|
421
|
+
scope.UnsetTag("page.locale");
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Default tags for ALL events (set in options)
|
|
425
|
+
SentrySdk.Init(options =>
|
|
426
|
+
{
|
|
427
|
+
options.DefaultTags["app.version"] = "2.0.1";
|
|
428
|
+
options.DefaultTags["deployment.region"] = "us-east-1";
|
|
429
|
+
});
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
**Tag constraints:** Keys ≤ 32 chars (`a-zA-Z`, `0-9`, `_`, `.`, `:`, `-`); values ≤ 200
|
|
433
|
+
chars, no newlines.
|
|
434
|
+
|
|
435
|
+
### User
|
|
436
|
+
|
|
437
|
+
```csharp
|
|
438
|
+
SentrySdk.ConfigureScope(scope =>
|
|
439
|
+
{
|
|
440
|
+
scope.User = new SentryUser
|
|
441
|
+
{
|
|
442
|
+
Id = "42",
|
|
443
|
+
Username = "john.doe",
|
|
444
|
+
Email = "john.doe@example.com",
|
|
445
|
+
IpAddress = "{{auto}}" // let Sentry infer from the connection
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// Custom fields
|
|
449
|
+
scope.User.Other["account_type"] = "premium";
|
|
450
|
+
scope.User.Other["tenant_id"] = "acme-corp";
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// Clear user on logout
|
|
454
|
+
SentrySdk.ConfigureScope(scope => scope.User = new SentryUser());
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
**SentryUser properties:**
|
|
458
|
+
|
|
459
|
+
| Property | Type | Notes |
|
|
460
|
+
| ----------- | ----------------------------- | ---------------------------------------------------------------------------- |
|
|
461
|
+
| `Id` | `string?` | Internal identifier |
|
|
462
|
+
| `Username` | `string?` | Display label |
|
|
463
|
+
| `Email` | `string?` | Enables Gravatars and Sentry messaging |
|
|
464
|
+
| `IpAddress` | `string?` | `"{{auto}}"` to infer from connection; auto-set when `SendDefaultPii = true` |
|
|
465
|
+
| `Other` | `IDictionary<string, string>` | Arbitrary additional user data |
|
|
466
|
+
|
|
467
|
+
### Breadcrumbs
|
|
468
|
+
|
|
469
|
+
**Manual:**
|
|
470
|
+
|
|
471
|
+
```csharp
|
|
472
|
+
SentrySdk.AddBreadcrumb(
|
|
473
|
+
message: "User authenticated",
|
|
474
|
+
category: "auth",
|
|
475
|
+
level: BreadcrumbLevel.Info);
|
|
476
|
+
|
|
477
|
+
// With structured data
|
|
478
|
+
SentrySdk.AddBreadcrumb(
|
|
479
|
+
message: "User navigated to checkout",
|
|
480
|
+
category: "navigation",
|
|
481
|
+
type: "navigation",
|
|
482
|
+
data: new Dictionary<string, string>
|
|
483
|
+
{
|
|
484
|
+
["from"] = "/cart",
|
|
485
|
+
["to"] = "/checkout"
|
|
486
|
+
},
|
|
487
|
+
level: BreadcrumbLevel.Info);
|
|
488
|
+
|
|
489
|
+
// Using Breadcrumb object
|
|
490
|
+
var crumb = new Breadcrumb(
|
|
491
|
+
message: "Button clicked",
|
|
492
|
+
type: "user",
|
|
493
|
+
data: new Dictionary<string, string> { ["button_id"] = "submit" },
|
|
494
|
+
category: "ui.click",
|
|
495
|
+
level: BreadcrumbLevel.Info);
|
|
496
|
+
SentrySdk.AddBreadcrumb(crumb);
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**BreadcrumbLevel values:** `Debug`, `Info` (default), `Warning`, `Error`, `Fatal`
|
|
500
|
+
|
|
501
|
+
**Automatically captured breadcrumbs:**
|
|
502
|
+
|
|
503
|
+
| Source | Requires |
|
|
504
|
+
| ---------------- | ------------------------------------------------------ |
|
|
505
|
+
| HTTP requests | `SentryHttpMessageHandler` with `HttpClient` |
|
|
506
|
+
| Logs (Info+) | `Microsoft.Extensions.Logging`, Serilog, NLog, log4net |
|
|
507
|
+
| Database queries | EF6 or EF Core via DiagnosticSource |
|
|
508
|
+
| MAUI app events | Navigation, lifecycle, user interactions |
|
|
509
|
+
|
|
510
|
+
Max breadcrumbs: 100 (default).
|
|
511
|
+
Override with `options.MaxBreadcrumbs = 50`.
|
|
512
|
+
|
|
513
|
+
### Custom Contexts (Structured, Non-Searchable)
|
|
514
|
+
|
|
515
|
+
```csharp
|
|
516
|
+
SentrySdk.ConfigureScope(scope =>
|
|
517
|
+
{
|
|
518
|
+
scope.Contexts["character"] = new
|
|
519
|
+
{
|
|
520
|
+
Name = "Mighty Fighter",
|
|
521
|
+
Age = 19,
|
|
522
|
+
AttackType = "melee"
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
scope.Contexts["build"] = new
|
|
526
|
+
{
|
|
527
|
+
Version = "2.0.1",
|
|
528
|
+
Commit = "abc123",
|
|
529
|
+
Pipeline = "main-ci"
|
|
530
|
+
};
|
|
531
|
+
});
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
> The key `"type"` is **reserved** — do not use it.
|
|
535
|
+
> Contexts are not searchable; use Tags for searchable data.
|
|
536
|
+
|
|
537
|
+
### Tags vs Contexts vs Extra
|
|
538
|
+
|
|
539
|
+
| Feature | Searchable? | Indexed? | Best For |
|
|
540
|
+
| ------------------ | ------------ | -------- | -------------------------------------- |
|
|
541
|
+
| **Tags** | ✅ Yes | ✅ Yes | Filtering, grouping, alerting |
|
|
542
|
+
| **Contexts** | ❌ No | ❌ No | Structured debug info (nested objects) |
|
|
543
|
+
| **Extra** (legacy) | ❌ No | ❌ No | Prefer `Contexts` instead |
|
|
544
|
+
| **User** | ✅ Partially | ✅ Yes | User attribution and filtering |
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
## `BeforeSend` and Filtering Hooks
|
|
549
|
+
|
|
550
|
+
### `BeforeSend` — Modify or Drop Error Events
|
|
551
|
+
|
|
552
|
+
Called immediately before transmission — last in the processing pipeline.
|
|
553
|
+
Return `null` to drop the event.
|
|
554
|
+
|
|
555
|
+
```csharp
|
|
556
|
+
SentrySdk.Init(options =>
|
|
557
|
+
{
|
|
558
|
+
// Simple variant
|
|
559
|
+
options.SetBeforeSend(@event =>
|
|
560
|
+
{
|
|
561
|
+
// Drop noisy exceptions
|
|
562
|
+
if (@event.Exception?.Message.Contains("Noisy Exception") == true)
|
|
563
|
+
return null;
|
|
564
|
+
|
|
565
|
+
// Scrub server name for privacy
|
|
566
|
+
@event.ServerName = null;
|
|
567
|
+
|
|
568
|
+
return @event;
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// Full variant with SentryHint
|
|
572
|
+
options.SetBeforeSend((@event, hint) =>
|
|
573
|
+
{
|
|
574
|
+
if (@event.Exception is SqlException sqlEx && sqlEx.Number == 1205)
|
|
575
|
+
{
|
|
576
|
+
// Deadlock — enrich rather than drop
|
|
577
|
+
@event.SetTag("sql.error_number", sqlEx.Number.ToString());
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return @event;
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
### `BeforeSendTransaction` — Modify or Drop Performance Events
|
|
586
|
+
|
|
587
|
+
```csharp
|
|
588
|
+
options.SetBeforeSendTransaction((transaction, hint) =>
|
|
589
|
+
{
|
|
590
|
+
if (transaction.Name == "GET /health")
|
|
591
|
+
return null; // Drop health-check transactions
|
|
592
|
+
return transaction;
|
|
593
|
+
});
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### `BeforeBreadcrumb` — Filter or Modify Breadcrumbs
|
|
597
|
+
|
|
598
|
+
```csharp
|
|
599
|
+
options.SetBeforeBreadcrumb(breadcrumb =>
|
|
600
|
+
breadcrumb.Category == "Spammy.Logger"
|
|
601
|
+
? null // null DROPS the breadcrumb
|
|
602
|
+
: breadcrumb); // returning it KEEPS it (optionally modified)
|
|
603
|
+
|
|
604
|
+
// Full variant with hint
|
|
605
|
+
options.SetBeforeBreadcrumb((breadcrumb, hint) =>
|
|
606
|
+
{
|
|
607
|
+
if (breadcrumb.Level == BreadcrumbLevel.Debug)
|
|
608
|
+
return null;
|
|
609
|
+
return breadcrumb;
|
|
610
|
+
});
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### `BeforeSendLog`
|
|
614
|
+
|
|
615
|
+
```csharp
|
|
616
|
+
options.SetBeforeSendLog(log =>
|
|
617
|
+
{
|
|
618
|
+
if (log.Level < SentryLogLevel.Warning)
|
|
619
|
+
return null;
|
|
620
|
+
return log;
|
|
621
|
+
});
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
## Fingerprinting and Custom Grouping
|
|
627
|
+
|
|
628
|
+
All events have a fingerprint.
|
|
629
|
+
Events with the same fingerprint group into the same issue.
|
|
630
|
+
The default fingerprint is computed from the stack trace.
|
|
631
|
+
Override it in `BeforeSend` or directly on a scope/event.
|
|
632
|
+
|
|
633
|
+
### Group more aggressively (collapse all matching into one issue)
|
|
634
|
+
|
|
635
|
+
```csharp
|
|
636
|
+
options.SetBeforeSend(@event =>
|
|
637
|
+
{
|
|
638
|
+
if (@event.Exception is SqlConnectionException)
|
|
639
|
+
{
|
|
640
|
+
// All SqlConnectionExceptions → one issue
|
|
641
|
+
@event.SetFingerprint(new[] { "database-connection-error" });
|
|
642
|
+
}
|
|
643
|
+
return @event;
|
|
644
|
+
});
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Group with greater granularity (split issues using `{{ default }}`)
|
|
648
|
+
|
|
649
|
+
```csharp
|
|
650
|
+
options.SetBeforeSend(@event =>
|
|
651
|
+
{
|
|
652
|
+
if (@event.Exception is MyRpcException ex)
|
|
653
|
+
{
|
|
654
|
+
@event.SetFingerprint(new[]
|
|
655
|
+
{
|
|
656
|
+
"{{ default }}", // keep Sentry's default hash
|
|
657
|
+
ex.Function, // split by RPC function
|
|
658
|
+
ex.Code.ToString() // split by status code
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
return @event;
|
|
662
|
+
});
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### Set fingerprint directly on scope or event
|
|
666
|
+
|
|
667
|
+
```csharp
|
|
668
|
+
// On scope — applies to all subsequent events in this scope
|
|
669
|
+
SentrySdk.ConfigureScope(scope =>
|
|
670
|
+
{
|
|
671
|
+
scope.Fingerprint = new[] { "my-custom-fingerprint" };
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
// On a specific event
|
|
675
|
+
var evt = new SentryEvent(exception);
|
|
676
|
+
evt.Fingerprint = new[] { "{{ default }}", "additional-key" };
|
|
677
|
+
SentrySdk.CaptureEvent(evt);
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
### Fingerprint template variables
|
|
681
|
+
|
|
682
|
+
| Variable | Description |
|
|
683
|
+
| ------------------- | ------------------------------------------------------------ |
|
|
684
|
+
| `{{ default }}` | Sentry’s normally computed hash (extend rather than replace) |
|
|
685
|
+
| `{{ transaction }}` | Current transaction name |
|
|
686
|
+
| `{{ function }}` | Top function in stack trace |
|
|
687
|
+
| `{{ type }}` | Exception type name |
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
## Exception Filters
|
|
692
|
+
|
|
693
|
+
### Filter by exception type
|
|
694
|
+
|
|
695
|
+
```csharp
|
|
696
|
+
SentrySdk.Init(options =>
|
|
697
|
+
{
|
|
698
|
+
// Also suppresses TaskCanceledException (derives from OperationCanceledException)
|
|
699
|
+
options.AddExceptionFilterForType<OperationCanceledException>();
|
|
700
|
+
options.AddExceptionFilterForType<MyBusinessException>();
|
|
701
|
+
});
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
### Custom `IExceptionFilter`
|
|
705
|
+
|
|
706
|
+
```csharp
|
|
707
|
+
public class MyExceptionFilter : IExceptionFilter
|
|
708
|
+
{
|
|
709
|
+
public bool Filter(Exception ex)
|
|
710
|
+
{
|
|
711
|
+
// Return true to DROP the exception (not sent to Sentry)
|
|
712
|
+
return ex is MyCustomException mce && mce.IsExpected;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
SentrySdk.Init(options =>
|
|
717
|
+
{
|
|
718
|
+
options.AddExceptionFilter(new MyExceptionFilter());
|
|
719
|
+
});
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
### Deduplication
|
|
723
|
+
|
|
724
|
+
```csharp
|
|
725
|
+
SentrySdk.Init(options =>
|
|
726
|
+
{
|
|
727
|
+
// Default: All ^ InnerException
|
|
728
|
+
options.DeduplicateMode =
|
|
729
|
+
DeduplicateMode.SameEvent |
|
|
730
|
+
DeduplicateMode.SameExceptionInstance;
|
|
731
|
+
|
|
732
|
+
// Disable entirely
|
|
733
|
+
options.DisableDuplicateEventDetection();
|
|
734
|
+
});
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
**DeduplicateMode flags:** `SameEvent`, `SameExceptionInstance`, `InnerException`,
|
|
738
|
+
`AggregateException`, `All`
|
|
739
|
+
|
|
740
|
+
---
|
|
741
|
+
|
|
742
|
+
## Unhandled Exception Capture
|
|
743
|
+
|
|
744
|
+
### WPF
|
|
745
|
+
|
|
746
|
+
```csharp
|
|
747
|
+
// App.xaml.cs — must be in constructor, NOT OnStartup()
|
|
748
|
+
public partial class App : Application
|
|
749
|
+
{
|
|
750
|
+
public App()
|
|
751
|
+
{
|
|
752
|
+
SentrySdk.Init(options =>
|
|
753
|
+
{
|
|
754
|
+
options.Dsn = "https://...@sentry.io/...";
|
|
755
|
+
options.IsGlobalModeEnabled = true; // Required for desktop apps
|
|
756
|
+
options.TracesSampleRate = 1.0;
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
// Hook WPF dispatcher-level unhandled exceptions
|
|
760
|
+
DispatcherUnhandledException += App_DispatcherUnhandledException;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
void App_DispatcherUnhandledException(
|
|
764
|
+
object sender, DispatcherUnhandledExceptionEventArgs e)
|
|
765
|
+
{
|
|
766
|
+
SentrySdk.CaptureException(e.Exception);
|
|
767
|
+
e.Handled = true; // Prevent the WPF default crash dialog
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
> **`IsGlobalModeEnabled = true`** is required for WPF — ensures background thread
|
|
773
|
+
> exceptions share the same scope as the UI thread.
|
|
774
|
+
|
|
775
|
+
> **Critical:** Initialize in the `App()` constructor, not `OnStartup()`. The
|
|
776
|
+
> constructor runs before any dispatcher frames, ensuring the unhandled exception hook
|
|
777
|
+
> is registered first.
|
|
778
|
+
|
|
779
|
+
### MAUI
|
|
780
|
+
|
|
781
|
+
```csharp
|
|
782
|
+
// MauiProgram.cs
|
|
783
|
+
public static MauiApp CreateMauiApp()
|
|
784
|
+
{
|
|
785
|
+
var builder = MauiApp.CreateBuilder();
|
|
786
|
+
builder
|
|
787
|
+
.UseMauiApp<App>()
|
|
788
|
+
.UseSentry(options =>
|
|
789
|
+
{
|
|
790
|
+
options.Dsn = "https://...@sentry.io/...";
|
|
791
|
+
options.TracesSampleRate = 1.0;
|
|
792
|
+
|
|
793
|
+
// Optional — all false by default (PII risk)
|
|
794
|
+
options.IncludeTextInBreadcrumbs = false;
|
|
795
|
+
options.IncludeTitleInBreadcrumbs = false;
|
|
796
|
+
options.IncludeBackgroundingStateInBreadcrumbs = false;
|
|
797
|
+
});
|
|
798
|
+
return builder.Build();
|
|
799
|
+
}
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
**MAUI platform coverage:**
|
|
803
|
+
|
|
804
|
+
| Platform | Integration |
|
|
805
|
+
| ------------------ | ------------------------------------------------------------------------------- |
|
|
806
|
+
| Android | `AppDomainUnhandledExceptionIntegration` + native Android SDK |
|
|
807
|
+
| iOS / Mac Catalyst | `RuntimeMarshalManagedExceptionIntegration` + native Cocoa SDK |
|
|
808
|
+
| Windows (WinUI) | `AppDomainUnhandledExceptionIntegration` + `WinUIUnhandledExceptionIntegration` |
|
|
809
|
+
|
|
810
|
+
### Windows Forms
|
|
811
|
+
|
|
812
|
+
```csharp
|
|
813
|
+
// Program.cs
|
|
814
|
+
[STAThread]
|
|
815
|
+
static void Main()
|
|
816
|
+
{
|
|
817
|
+
Application.EnableVisualStyles();
|
|
818
|
+
Application.SetCompatibleTextRenderingDefault(false);
|
|
819
|
+
|
|
820
|
+
// REQUIRED: makes WinForms re-throw instead of swallowing exceptions
|
|
821
|
+
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
|
|
822
|
+
|
|
823
|
+
using (SentrySdk.Init(options =>
|
|
824
|
+
{
|
|
825
|
+
options.Dsn = "https://...@sentry.io/...";
|
|
826
|
+
options.IsGlobalModeEnabled = true;
|
|
827
|
+
options.TracesSampleRate = 1.0;
|
|
828
|
+
}))
|
|
829
|
+
{
|
|
830
|
+
Application.Run(new MainForm());
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
### Console App
|
|
836
|
+
|
|
837
|
+
```csharp
|
|
838
|
+
// Program.cs
|
|
839
|
+
SentrySdk.Init(options =>
|
|
840
|
+
{
|
|
841
|
+
options.Dsn = "https://...@sentry.io/...";
|
|
842
|
+
options.TracesSampleRate = 1.0;
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
// SDK 3.31.0+ handles flush on exit automatically
|
|
846
|
+
// For older SDKs, wrap in: using var _ = SentrySdk.Init(...);
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
### Disabling Built-in Integrations
|
|
850
|
+
|
|
851
|
+
```csharp
|
|
852
|
+
SentrySdk.Init(options =>
|
|
853
|
+
{
|
|
854
|
+
options.DisableAppDomainUnhandledExceptionCapture();
|
|
855
|
+
options.DisableUnobservedTaskExceptionCapture();
|
|
856
|
+
options.DisableAppDomainProcessExitFlush();
|
|
857
|
+
options.DisableRuntimeMarshalManagedExceptionCapture(); // iOS/MacCatalyst
|
|
858
|
+
});
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
---
|
|
862
|
+
|
|
863
|
+
## Event Processors
|
|
864
|
+
|
|
865
|
+
Unlike `BeforeSend` (only one allowed), multiple event processors can be registered at
|
|
866
|
+
different scopes:
|
|
867
|
+
|
|
868
|
+
```csharp
|
|
869
|
+
// Global — runs for all events
|
|
870
|
+
public class MyEventProcessor : ISentryEventProcessor
|
|
871
|
+
{
|
|
872
|
+
public SentryEvent? Process(SentryEvent @event)
|
|
873
|
+
{
|
|
874
|
+
if (@event.Exception is BackgroundJobException)
|
|
875
|
+
return null; // Drop — null discards the event
|
|
876
|
+
|
|
877
|
+
@event.SetTag("app.layer", "background-worker");
|
|
878
|
+
@event.ServerName = null; // Scrub hostname
|
|
879
|
+
|
|
880
|
+
return @event;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Register globally via options
|
|
885
|
+
SentrySdk.Init(options =>
|
|
886
|
+
{
|
|
887
|
+
options.AddEventProcessor(new MyEventProcessor());
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
// Register on current + following scopes
|
|
891
|
+
SentrySdk.ConfigureScope(scope =>
|
|
892
|
+
{
|
|
893
|
+
scope.AddEventProcessor(new MyEventProcessor());
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
// Register for a single event only
|
|
897
|
+
SentrySdk.CaptureException(ex, scope =>
|
|
898
|
+
{
|
|
899
|
+
scope.AddEventProcessor(new MyEventProcessor());
|
|
900
|
+
});
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
### Exception processor (runs before the main chain)
|
|
904
|
+
|
|
905
|
+
```csharp
|
|
906
|
+
public class MyExceptionProcessor : ISentryEventExceptionProcessor
|
|
907
|
+
{
|
|
908
|
+
public void Process(Exception exception, SentryEvent sentryEvent)
|
|
909
|
+
{
|
|
910
|
+
if (exception is HttpRequestException httpEx)
|
|
911
|
+
{
|
|
912
|
+
sentryEvent.SetTag("http.status", httpEx.StatusCode?.ToString() ?? "unknown");
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
SentrySdk.Init(options =>
|
|
918
|
+
{
|
|
919
|
+
options.AddExceptionProcessor(new MyExceptionProcessor());
|
|
920
|
+
});
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
**Processor execution order:**
|
|
924
|
+
|
|
925
|
+
1. `ISentryEventExceptionProcessor` — exception-specific processors
|
|
926
|
+
2. `ISentryEventProcessor` — general event processors
|
|
927
|
+
3. `SetBeforeSend` / `SetBeforeSendTransaction` — **always last**
|
|
928
|
+
|
|
929
|
+
---
|
|
930
|
+
|
|
931
|
+
## User Feedback
|
|
932
|
+
|
|
933
|
+
### Programmatic API
|
|
934
|
+
|
|
935
|
+
```csharp
|
|
936
|
+
// Capture an event first to get an ID
|
|
937
|
+
var eventId = SentrySdk.CaptureMessage("An event that will receive user feedback.");
|
|
938
|
+
|
|
939
|
+
// Submit user feedback linked to that event
|
|
940
|
+
SentrySdk.CaptureFeedback(
|
|
941
|
+
message: "It broke when I clicked submit.",
|
|
942
|
+
contactEmail: "user@example.com",
|
|
943
|
+
name: "Jane Doe",
|
|
944
|
+
associatedEventId: eventId);
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
**Full signature:**
|
|
948
|
+
|
|
949
|
+
```csharp
|
|
950
|
+
SentryId SentrySdk.CaptureFeedback(
|
|
951
|
+
string message,
|
|
952
|
+
string? contactEmail = null,
|
|
953
|
+
string? name = null,
|
|
954
|
+
string? replayId = null,
|
|
955
|
+
string? url = null,
|
|
956
|
+
SentryId? associatedEventId = null,
|
|
957
|
+
Scope? scope = null,
|
|
958
|
+
SentryHint? hint = null)
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
**Using `SentryFeedback` object:**
|
|
962
|
+
|
|
963
|
+
```csharp
|
|
964
|
+
var feedback = new SentryFeedback(
|
|
965
|
+
message: "The checkout button is broken.",
|
|
966
|
+
contactEmail: "user@example.com",
|
|
967
|
+
name: "John Smith",
|
|
968
|
+
associatedEventId: SentrySdk.LastEventId);
|
|
969
|
+
|
|
970
|
+
SentrySdk.CaptureFeedback(feedback);
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
> **Validation:** Sentry rejects feedback with invalid email addresses.
|
|
974
|
+
> Pre-validate email format before calling the API.
|
|
975
|
+
|
|
976
|
+
### Crash-Report Modal (JavaScript widget on error pages)
|
|
977
|
+
|
|
978
|
+
For ASP.NET Core web apps, show the browser-based report dialog on error response pages:
|
|
979
|
+
|
|
980
|
+
```html
|
|
981
|
+
<!-- Include Sentry JS SDK -->
|
|
982
|
+
<script src="https://browser.sentry-cdn.com/10.40.0/bundle.min.js" crossorigin="anonymous"></script>
|
|
983
|
+
|
|
984
|
+
<!-- Show dialog with the server-side event ID -->
|
|
985
|
+
<script>
|
|
986
|
+
Sentry.init({ dsn: "https://...@sentry.io/..." });
|
|
987
|
+
Sentry.showReportDialog({ eventId: "@ViewBag.SentryEventId" });
|
|
988
|
+
</script>
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
```csharp
|
|
992
|
+
// In your error controller or exception handler middleware
|
|
993
|
+
ViewBag.SentryEventId = SentrySdk.LastEventId;
|
|
994
|
+
```
|
|
995
|
+
|
|
996
|
+
---
|
|
997
|
+
|
|
998
|
+
## Error Capture Quick Reference
|
|
999
|
+
|
|
1000
|
+
### Scenario Coverage Table
|
|
1001
|
+
|
|
1002
|
+
| Scenario | Auto Captured? | Solution |
|
|
1003
|
+
| ------------------------------------ | -------------- | ---------------------------------------------------- |
|
|
1004
|
+
| Unhandled exception (all frameworks) | ✅ Yes | `AppDomain.UnhandledException` integration |
|
|
1005
|
+
| Unobserved Task exception | ✅ Yes | `TaskScheduler.UnobservedTaskException` integration |
|
|
1006
|
+
| ASP.NET Core request error | ✅ Yes | Sentry middleware |
|
|
1007
|
+
| WPF `DispatcherUnhandledException` | ✅ Yes | Hook in `App()` constructor |
|
|
1008
|
+
| MAUI unhandled exception | ✅ Yes | Platform-specific native integrations |
|
|
1009
|
+
| WinForms unhandled exception | ✅ Yes | Requires `SetUnhandledExceptionMode(ThrowException)` |
|
|
1010
|
+
| `try/catch` with graceful return | ❌ No | `SentrySdk.CaptureException(ex)` before return |
|
|
1011
|
+
| `try/catch` with re-throw | ✅ Yes | Bubbles to unhandled exception handler |
|
|
1012
|
+
| Background thread exception | ✅ Yes | `IsGlobalModeEnabled = true` for desktop apps |
|
|
1013
|
+
|
|
1014
|
+
### API Quick Reference
|
|
1015
|
+
|
|
1016
|
+
```csharp
|
|
1017
|
+
// ── Capture ───────────────────────────────────────────────────────────────
|
|
1018
|
+
SentrySdk.CaptureException(ex)
|
|
1019
|
+
SentrySdk.CaptureException(ex, scope => { scope.SetTag("key", "val"); })
|
|
1020
|
+
SentrySdk.CaptureMessage("text")
|
|
1021
|
+
SentrySdk.CaptureMessage("text", SentryLevel.Warning)
|
|
1022
|
+
|
|
1023
|
+
// ── User ──────────────────────────────────────────────────────────────────
|
|
1024
|
+
SentrySdk.ConfigureScope(scope => scope.User = new SentryUser { Id = "42", Email = "..." });
|
|
1025
|
+
SentrySdk.ConfigureScope(scope => scope.User = new SentryUser()); // clear on logout
|
|
1026
|
+
|
|
1027
|
+
// ── Tags (searchable) ─────────────────────────────────────────────────────
|
|
1028
|
+
SentrySdk.ConfigureScope(scope => scope.SetTag("key", "value"));
|
|
1029
|
+
SentrySdk.ConfigureScope(scope => scope.UnsetTag("key"));
|
|
1030
|
+
|
|
1031
|
+
// ── Contexts (structured, non-searchable) ─────────────────────────────────
|
|
1032
|
+
SentrySdk.ConfigureScope(scope => scope.Contexts["name"] = new { Key = "value" });
|
|
1033
|
+
|
|
1034
|
+
// ── Breadcrumbs ───────────────────────────────────────────────────────────
|
|
1035
|
+
SentrySdk.AddBreadcrumb(message: "...", category: "auth", level: BreadcrumbLevel.Info);
|
|
1036
|
+
|
|
1037
|
+
// ── Scope isolation ───────────────────────────────────────────────────────
|
|
1038
|
+
using (SentrySdk.PushScope())
|
|
1039
|
+
{
|
|
1040
|
+
SentrySdk.ConfigureScope(scope => scope.SetTag("key", "value"));
|
|
1041
|
+
SentrySdk.CaptureException(ex);
|
|
1042
|
+
} // tag is cleared after this block
|
|
1043
|
+
|
|
1044
|
+
// ── Fingerprinting ────────────────────────────────────────────────────────
|
|
1045
|
+
SentrySdk.ConfigureScope(scope => scope.Fingerprint = new[] { "group-key" });
|
|
1046
|
+
// In BeforeSend: @event.SetFingerprint(new[] { "{{ default }}", "extra-dim" });
|
|
1047
|
+
|
|
1048
|
+
// ── Hooks (in SentrySdk.Init) ─────────────────────────────────────────────
|
|
1049
|
+
options.SetBeforeSend((@event, hint) => @event) // return null to drop
|
|
1050
|
+
options.SetBeforeSendTransaction((txn, hint) => txn)
|
|
1051
|
+
options.SetBeforeBreadcrumb((crumb, hint) => crumb) // return null to drop
|
|
1052
|
+
options.AddExceptionFilterForType<OperationCanceledException>()
|
|
1053
|
+
|
|
1054
|
+
// ── Flush ─────────────────────────────────────────────────────────────────
|
|
1055
|
+
SentrySdk.Flush(TimeSpan.FromSeconds(5));
|
|
1056
|
+
await SentrySdk.FlushAsync(TimeSpan.FromSeconds(5));
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
---
|
|
1060
|
+
|
|
1061
|
+
## Configuration Options Reference
|
|
1062
|
+
|
|
1063
|
+
| Option | Type | Default | Description |
|
|
1064
|
+
| ----------------------- | ---------------------------- | ---------------------- | ----------------------------------------------------------------- |
|
|
1065
|
+
| `Dsn` | `string` | — | DSN from Sentry project settings; also reads `SENTRY_DSN` env var |
|
|
1066
|
+
| `Release` | `string?` | — | App release version; also reads `SENTRY_RELEASE` |
|
|
1067
|
+
| `Environment` | `string?` | — | Deployment environment; also reads `SENTRY_ENVIRONMENT` |
|
|
1068
|
+
| `SampleRate` | `float?` | `null` (sends 100%) | Error event sampling rate (0–1) |
|
|
1069
|
+
| `TracesSampleRate` | `double?` | `null` (tracing off) | Transaction sampling rate (0–1) |
|
|
1070
|
+
| `AttachStacktrace` | `bool` | `true` | Attach stack traces to message events too |
|
|
1071
|
+
| `SendDefaultPii` | `bool` | `false` | Include IP, username, headers |
|
|
1072
|
+
| `MaxBreadcrumbs` | `int` | `100` | Max breadcrumbs per event |
|
|
1073
|
+
| `IsGlobalModeEnabled` | `bool` | `false` | Singleton scope for desktop apps |
|
|
1074
|
+
| `Debug` | `bool` | `false` | Log SDK diagnostics to console |
|
|
1075
|
+
| `DiagnosticLevel` | `SentryLevel` | `Debug` | Min level for SDK diagnostic logs |
|
|
1076
|
+
| `DeduplicateMode` | `DeduplicateMode` | `All ^ InnerException` | Duplicate event detection strategy |
|
|
1077
|
+
| `MaxAttachmentSize` | `long` | `20 MiB` | Max attachment size in bytes |
|
|
1078
|
+
| `DefaultTags` | `Dictionary<string, string>` | `{}` | Tags added to every event |
|
|
1079
|
+
| `CacheDirectoryPath` | `string?` | `null` | Path for offline envelope caching |
|
|
1080
|
+
| `ShutdownTimeout` | `TimeSpan` | `2s` | Flush timeout on SDK shutdown |
|
|
1081
|
+
| `CaptureFailedRequests` | `bool` | `true` | Capture HTTP client error responses |
|
|
1082
|
+
| `EnableLogs` | `bool` | `false` | Enable Sentry structured logging |
|
|
1083
|
+
| `StackTraceMode` | `StackTraceMode` | `Enhanced` | `Enhanced` or `Original` |
|
|
1084
|
+
|
|
1085
|
+
---
|
|
1086
|
+
|
|
1087
|
+
## Troubleshooting
|
|
1088
|
+
|
|
1089
|
+
| Issue | Solution |
|
|
1090
|
+
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
1091
|
+
| Caught exceptions not appearing in Sentry | Any `try/catch` that doesn’t re-throw must call `SentrySdk.CaptureException(ex)` before returning |
|
|
1092
|
+
| WPF exceptions from background threads missing | Set `options.IsGlobalModeEnabled = true`; initialize in `App()` constructor, not `OnStartup()` |
|
|
1093
|
+
| WinForms exceptions not captured | Call `Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException)` before `SentrySdk.Init` |
|
|
1094
|
+
| Events dropped after process exit (console/CLI) | SDK 3.31.0+ handles this automatically; on older versions wrap `Init` result in `using var _ = SentrySdk.Init(...)` |
|
|
1095
|
+
| Stack traces show minified/optimized frames | Enable symbol upload via MSBuild properties (`SentryOrg`, `SentryProject`, `SentryAuthToken`) |
|
|
1096
|
+
| Duplicate events in Sentry | Check `DeduplicateMode`; `AggregateException` wrapping can cause same exception to appear multiple times |
|
|
1097
|
+
| Missing user data on events | For ASP.NET Core, enable `SendDefaultPii = true` or register a custom `ISentryUserFactory`; for desktop apps ensure `IsGlobalModeEnabled = true` |
|
|
1098
|
+
| `OperationCanceledException` flooding Sentry | Filter with `options.AddExceptionFilterForType<OperationCanceledException>()` |
|
|
1099
|
+
| Events not sent before Lambda/Azure Functions cold start ends | Call `await SentrySdk.FlushAsync(TimeSpan.FromSeconds(5))` at the end of your handler |
|
|
1100
|
+
| SDK reports `IsEnabled = false` | DSN not set or set to empty string; check `SENTRY_DSN` env var or options initialization order |
|