Claude-code-plugins-plus sentry-sdk-patterns
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/sentry-pack/skills/sentry-sdk-patterns" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-sentry-sdk-patterns && rm -rf "$T"
manifest:
plugins/saas-packs/sentry-pack/skills/sentry-sdk-patterns/SKILL.mdsource content
Sentry SDK Patterns
Overview
Production patterns for
@sentry/node (v8+) and sentry-sdk (Python 2.x+) covering scoped error context, breadcrumb strategies, event filtering with beforeSend, custom fingerprinting for issue grouping, and performance instrumentation with spans. All examples use real Sentry SDK APIs.
Prerequisites
- Sentry SDK v8+ installed (
,@sentry/node
, or@sentry/react
)sentry-sdk
environment variable configuredSENTRY_DSN- Familiarity with async/await (TypeScript) or context managers (Python)
Instructions
Step 1 -- Structured Error Context with Scopes
Use
Sentry.withScope() (TypeScript) or sentry_sdk.new_scope() (Python) to attach context to individual events without leaking state across requests.
TypeScript -- Scoped error capture:
import * as Sentry from '@sentry/node'; type ErrorSeverity = 'low' | 'medium' | 'high' | 'critical'; interface ErrorOptions { severity?: ErrorSeverity; tags?: Record<string, string>; context?: Record<string, unknown>; user?: { id: string; email?: string }; fingerprint?: string[]; } const SEVERITY_MAP: Record<ErrorSeverity, Sentry.SeverityLevel> = { low: 'info', medium: 'warning', high: 'error', critical: 'fatal', }; export function captureError(error: Error, options: ErrorOptions = {}) { Sentry.withScope((scope) => { scope.setLevel(SEVERITY_MAP[options.severity || 'medium']); if (options.tags) { Object.entries(options.tags).forEach(([key, value]) => { scope.setTag(key, value); }); } if (options.context) { scope.setContext('app', options.context); } if (options.user) { scope.setUser(options.user); } if (options.fingerprint) { scope.setFingerprint(options.fingerprint); } Sentry.captureException(error); }); }
Python -- Scoped error capture:
import sentry_sdk def capture_error(error, severity="error", tags=None, context=None, user=None): """Capture exception with isolated scope context.""" with sentry_sdk.new_scope() as scope: scope.set_level(severity) if tags: for key, value in tags.items(): scope.set_tag(key, value) if context: scope.set_context("app", context) if user: scope.set_user(user) sentry_sdk.capture_exception(error)
Key rule: Never call
Sentry.setTag() or sentry_sdk.set_tag() at the module level inside request handlers. Those mutate the global scope and leak between concurrent requests. Always use withScope() or new_scope().
Step 2 -- Breadcrumbs, Filtering, and Fingerprints
Structured breadcrumb helpers
import * as Sentry from '@sentry/node'; export const breadcrumb = { auth(action: string, userId?: string) { Sentry.addBreadcrumb({ category: 'auth', message: `${action}${userId ? ` for user ${userId}` : ''}`, level: 'info', }); }, db(operation: string, table: string, durationMs?: number) { Sentry.addBreadcrumb({ category: 'db', message: `${operation} on ${table}`, level: 'info', data: { table, operation, ...(durationMs && { duration_ms: durationMs }) }, }); }, http(method: string, url: string, status: number) { Sentry.addBreadcrumb({ category: 'http', message: `${method} ${url} -> ${status}`, level: status >= 400 ? 'warning' : 'info', data: { method, url, status_code: status }, }); }, };
Python breadcrumbs:
sentry_sdk.add_breadcrumb( category="auth", message="User logged in", level="info", data={"user_id": user_id, "method": "oauth"}, )
beforeSend -- Drop noise, scrub PII
Sentry.init({ dsn: process.env.SENTRY_DSN, beforeSend(event, hint) { const error = hint?.originalException; // Drop non-actionable errors if (error instanceof Error) { if (error.message.includes('ResizeObserver loop')) return null; if (error.message.includes('Network request failed')) return null; } // Scrub PII from user context if (event.user) { delete event.user.ip_address; delete event.user.email; } return event; }, });
Python beforeSend:
def before_send(event, hint): if "exc_info" in hint: exc_type, exc_value, tb = hint["exc_info"] if isinstance(exc_value, (KeyboardInterrupt, SystemExit)): return None if "user" in event: event["user"].pop("email", None) event["user"].pop("ip_address", None) return event sentry_sdk.init(dsn=os.environ["SENTRY_DSN"], before_send=before_send)
beforeBreadcrumb -- Filter noisy breadcrumbs
Sentry.init({ dsn: process.env.SENTRY_DSN, beforeBreadcrumb(breadcrumb, hint) { // Drop console.log breadcrumbs in production if (breadcrumb.category === 'console' && breadcrumb.level === 'log') { return null; } // Redact auth tokens from HTTP breadcrumbs if (breadcrumb.category === 'fetch' && breadcrumb.data?.url) { const url = new URL(breadcrumb.data.url); url.searchParams.delete('token'); breadcrumb.data.url = url.toString(); } return breadcrumb; }, });
Custom fingerprints for issue grouping
Override default stack-trace grouping when the same root cause produces different stacks:
Sentry.withScope((scope) => { // Group all payment gateway timeouts together scope.setFingerprint(['payment-gateway-timeout', gatewayName]); Sentry.captureException(error); });
with sentry_sdk.new_scope() as scope: scope.fingerprint = ["payment-gateway-timeout", gateway_name] sentry_sdk.capture_exception(error)
Step 3 -- Framework Integration and Performance Spans
Express middleware (Sentry v8)
import * as Sentry from '@sentry/node'; import express from 'express'; const app = express(); // Sentry v8: register error handler Sentry.setupExpressErrorHandler(app); // Request context middleware (register BEFORE routes) app.use((req, res, next) => { Sentry.setUser({ id: req.user?.id, ip_address: req.ip }); Sentry.addBreadcrumb({ category: 'http', message: `${req.method} ${req.path}`, data: { query: req.query, params: req.params }, }); next(); });
React Error Boundary
import * as Sentry from '@sentry/react'; const SentryErrorBoundary = Sentry.withErrorBoundary(App, { fallback: ({ error, resetError }) => ( <div> <h2>Something went wrong</h2> <button onClick={resetError}>Try again</button> </div> ), beforeCapture: (scope) => { scope.setTag('location', 'error-boundary'); scope.setLevel('fatal'); }, });
Performance spans (TypeScript)
async function processOrder(orderId: string) { return Sentry.startSpan( { name: 'processOrder', op: 'task', attributes: { orderId } }, async (span) => { const order = await Sentry.startSpan( { name: 'db.getOrder', op: 'db.query' }, () => db.orders.findById(orderId), ); await Sentry.startSpan( { name: 'payment.charge', op: 'http.client' }, () => chargePayment(order), ); span.setStatus({ code: 1, message: 'ok' }); return order; }, ); }
Performance spans (Python)
import sentry_sdk from functools import wraps def sentry_traced(op="function"): """Decorator to wrap functions in Sentry spans.""" def decorator(func): @wraps(func) def wrapper(*args, **kwargs): with sentry_sdk.start_span(op=op, name=func.__name__): return func(*args, **kwargs) return wrapper return decorator @sentry_traced(op="db.query") def get_user(user_id: str): return db.users.find_one({"_id": user_id})
Async batch processing with error isolation
async function processItems(items: Item[]) { const results = await Promise.allSettled( items.map((item) => Sentry.startSpan({ name: `process.${item.type}`, op: 'task' }, () => processItem(item), ), ), ); const failures = results.filter( (r): r is PromiseRejectedResult => r.status === 'rejected', ); if (failures.length > 0) { Sentry.withScope((scope) => { scope.setTag('batch_size', String(items.length)); scope.setTag('failure_count', String(failures.length)); Sentry.captureMessage(`${failures.length}/${items.length} items failed`, 'warning'); }); failures.forEach((f) => Sentry.captureException(f.reason)); } }
See implementation.md for Django middleware, test mocking patterns, and additional framework examples.
Output
After applying these patterns you will have:
- Centralized error handler module with typed severity and scoped context
- Structured breadcrumb helpers for auth, db, and http events
filter that drops noise and scrubs PIIbeforeSend
callback that redacts sensitive query parametersbeforeBreadcrumb- Custom fingerprinting for accurate issue grouping
- Framework error boundaries for Express and React
- Performance spans for tracing critical code paths
Error Handling
| Error | Cause | Solution |
|---|---|---|
| Scope leaking between requests | Global scope mutations in async handlers | Use / for per-event context |
| Duplicate events | Error caught and re-thrown at two layers | Capture at one level only -- middleware or handler, not both |
| Missing breadcrumbs | Cleared after max count (default 100) | Set in |
returns | Missing return statement | Always return or explicitly |
| Events grouped incorrectly | Default stack-trace fingerprinting | Use with semantic keys |
| SDK not imported | Verify |
| Spans not appearing | Missing tracing config | Set in |
Examples
Centralized error handler: Create
lib/error-handler.ts wrapping Sentry.withScope() with typed severity, tags, context, user, and fingerprint support.
Breadcrumb trail for checkout: Add
breadcrumb.auth('login'), breadcrumb.db('SELECT', 'orders'), breadcrumb.http('POST', '/api/payments', 201) before critical operations so errors include full context timeline.
Noise filtering: Configure
beforeSend to drop ResizeObserver loop and Network request failed, scrub PII from user context and cookies.
Fix issue grouping: Add
scope.setFingerprint(['payment-gateway-timeout', gatewayName]) to group all payment timeouts by gateway.
See examples.md for full worked scenarios with Python context managers and async wrappers.
Resources
- Sentry JavaScript SDK Best Practices
- Scopes and Context
- Express Integration Guide
- Python SDK Documentation
- Custom Fingerprinting
- Performance Monitoring
Next Steps
- sentry-error-capture -- Deep dive on
vscaptureException
semanticscaptureMessage - sentry-performance-tracing -- Full distributed tracing with
and custom instrumentationtracesSampleRate - sentry-data-handling -- PII scrubbing, data residency, and GDPR-compliant configuration
- sentry-common-errors -- Troubleshooting guide for frequent SDK issues