Sentry Best Practices
Sentry is our definitive platform for error tracking and performance monitoring. Proper integration ensures we debug faster, ship more reliably, and maintain high application health. This guide outlines the mandatory best practices for all projects.
1. Code Organization and Initialization
Always initialize the Sentry SDK early in your application's bootstrap process. This ensures maximum coverage for errors and performance tracing.
1.1. Early and Centralized Initialization
Initialize Sentry once, as close to your application's entry point as possible. Use environment variables for sensitive data like DSN and for configuration that varies by environment.
❌ BAD: Late or Scattered Initialization
# app/views.py (Django) or a random module
import sentry_sdk
def my_function():
if not sentry_sdk.is_initialized(): # Don't do this, it's too late and prone to race conditions
sentry_sdk.init(dsn="YOUR_DSN")
# ...
✅ GOOD: Application Bootstrap (Python Example)
# app.py or wsgi.py/asgi.py for web apps
import os
import sentry_sdk
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration # Example for Lambda
SENTRY_DSN = os.getenv("SENTRY_DSN")
SENTRY_ENVIRONMENT = os.getenv("SENTRY_ENVIRONMENT", "development")
SENTRY_RELEASE = os.getenv("SENTRY_RELEASE", "unknown")
SENTRY_TRACES_SAMPLE_RATE = float(os.getenv("SENTRY_TRACES_SAMPLE_RATE", "0.0")) # Default to 0.0 in prod
if SENTRY_DSN:
sentry_sdk.init(
dsn=SENTRY_DSN,
environment=SENTRY_ENVIRONMENT,
release=SENTRY_RELEASE,
enable_tracing=True, # Always enable tracing, sampling controls overhead
traces_sample_rate=SENTRY_TRACES_SAMPLE_RATE,
# Add integrations as needed, e.g., for specific frameworks or platforms
# integrations=[AwsLambdaIntegration()] if SENTRY_ENVIRONMENT == "aws-lambda" else [],
)
✅ GOOD: Application Bootstrap (JavaScript/TypeScript Example)
// src/index.ts or app.ts
import * as Sentry from "@sentry/node"; // or @sentry/browser, @sentry/react, etc.
const SENTRY_DSN = process.env.SENTRY_DSN;
const SENTRY_ENVIRONMENT = process.env.SENTRY_ENVIRONMENT || "development";
const SENTRY_RELEASE = process.env.SENTRY_RELEASE || "unknown";
const SENTRY_TRACES_SAMPLE_RATE = parseFloat(process.env.SENTRY_TRACES_SAMPLE_RATE || "0.0");
if (SENTRY_DSN) {
Sentry.init({
dsn: SENTRY_DSN,
environment: SENTRY_ENVIRONMENT,
release: SENTRY_RELEASE,
integrations: [
// Add framework-specific integrations here, e.g., new Sentry.Integrations.Http({ tracing: true })
// new Sentry.Integrations.Express(),
],
tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE,
enableTracing: true, // Redundant with tracesSampleRate > 0, but good for clarity
});
}
1.2. Environment, Release, and User Context
Always set environment and release during initialization. Enrich events with user and other relevant context for faster debugging.
✅ GOOD: Setting Context
import sentry_sdk
# ... Sentry init as above ...
def process_order(user_id: str, order_details: dict):
with sentry_sdk.push_scope() as scope: # Use push_scope for temporary context
scope.set_user({"id": user_id, "email": "user@example.com"})
scope.set_tag("order_type", "premium")
scope.set_context("order_details", order_details)
try:
# ... order processing logic ...
raise ValueError("Failed to process payment")
except Exception as e:
sentry_sdk.capture_exception(e)
2. Common Patterns and Anti-patterns
2.1. Performance Tracing with OpenTelemetry
Leverage OpenTelemetry for distributed tracing. Sentry SDKs integrate seamlessly, allowing end-to-end visibility without rewriting existing instrumentation.
✅ GOOD: OpenTelemetry Integration (Python Example)
import sentry_sdk
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
from sentry_sdk.integrations.opentelemetry import SentrySpanProcessor
# Configure OpenTelemetry
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter())) # For local debugging
provider.add_span_processor(SentrySpanProcessor()) # Send spans to Sentry
trace.set_tracer_provider(provider)
# Initialize Sentry (ensure enable_tracing and traces_sample_rate are set)
sentry_sdk.init(
dsn="YOUR_DSN",
enable_tracing=True,
traces_sample_rate=1.0, # Adjust for production
# ... other config ...
)
# Use OpenTelemetry tracer
tracer = trace.get_tracer(__name__)
def my_traced_function():
with tracer.start_as_current_span("my-custom-operation"):
print("Executing traced operation...")
# ... your code ...
2.2. Isolated Clients for Shared Environments (JavaScript/TypeScript)
NEVER use Sentry.init() in shared environments (e.g., browser extensions, VS Code extensions, third-party widgets). This pollutes global state and leads to data leakage. Create a dedicated client instance manually.
❌ BAD: Global Init in Shared Environment
// browser_extension/background.ts
import * as Sentry from "@sentry/browser";
Sentry.init({ // ❌ DANGER: Do NOT use Sentry.init() in shared environments!
dsn: "YOUR_DSN",
// ...
});
✅ GOOD: Manual Client Setup for Shared Environments
// browser_extension/background.ts
import {
BrowserClient,
defaultStackParser,
getDefaultIntegrations,
makeFetchTransport,
Scope,
} from "@sentry/browser";
// Filter out integrations that rely on global state
const integrations = getDefaultIntegrations({}).filter(
(defaultIntegration) =>
!["BrowserApiErrors", "Breadcrumbs", "GlobalHandlers"].includes(defaultIntegration.name)
);
const client = new BrowserClient({
dsn: "YOUR_DSN",
transport: makeFetchTransport,
stackParser: defaultStackParser,
integrations: integrations,
tracesSampleRate: 1.0, // Adjust for production
enableTracing: true,
});
const scope = new Scope();
scope.setClient(client);
client.init(); // Initialize the client after setting it on the scope
// Manually capture exceptions using the client's scope
try {
// Your extension code here
throw new Error("Example error in extension");
} catch (error) {
scope.captureException(error);
}
2.3. AWS Lambda Integration
For serverless functions, use the platform-specific integration.
✅ GOOD: AWS Lambda (Python Example)
import os
import sentry_sdk
from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration
SENTRY_DSN = os.getenv("SENTRY_DSN")
SENTRY_TRACES_SAMPLE_RATE = float(os.getenv("SENTRY_TRACES_SAMPLE_RATE", "0.0"))
if SENTRY_DSN:
sentry_sdk.init(
dsn=SENTRY_DSN,
integrations=[AwsLambdaIntegration()],
traces_sample_rate=SENTRY_TRACES_SAMPLE_RATE,
environment=os.getenv("SENTRY_ENVIRONMENT", "production"),
release=os.getenv("SENTRY_RELEASE", "unknown"),
)
def lambda_handler(event, context):
# Your Lambda function logic
print("Processing event...")
raise ValueError("Something went wrong in Lambda!")
return {"statusCode": 200, "body": "Success"}
3. Performance Considerations
3.1. Configure traces_sample_rate Judiciously
traces_sample_rate directly impacts performance overhead and Sentry quota usage.
- Development: Set to
1.0to capture all transactions for full visibility. - Production: Set to a lower value (e.g.,
0.01to0.1) to sample a representative subset of transactions. Adjust based on traffic volume and monitoring needs.
❌ BAD: traces_sample_rate=1.0 in Production
sentry_sdk.init(
dsn="YOUR_PROD_DSN",
traces_sample_rate=1.0, # ❌ This will send ALL traces, potentially incurring high costs and overhead.
enable_tracing=True,
)
✅ GOOD: Controlled Sampling in Production
sentry_sdk.init(
dsn="YOUR_PROD_DSN",
traces_sample_rate=0.05, # ✅ Sample 5% of transactions in production
enable_tracing=True,
)
4. Common Pitfalls and Gotchas
4.1. Missing or Invalid DSN
Without a valid DSN, Sentry cannot send events. Always verify your DSN is correctly configured, ideally via environment variables.
❌ BAD: Hardcoded or Missing DSN
sentry_sdk.init(
dsn="", # ❌ No DSN means no events
# ...
)
✅ GOOD: DSN from Environment Variables
import os
sentry_sdk.init(
dsn=os.getenv("SENTRY_DSN"), # ✅ Always load DSN from environment
# ...
)
4.2. Unset environment and release
Events without environment or release are significantly harder to triage and correlate. Always set these values.
❌ BAD: Omitting Environment/Release
sentry_sdk.init(
dsn="YOUR_DSN",
# No environment or release set ❌
)
✅ GOOD: Explicit Environment/Release
sentry_sdk.init(
dsn="YOUR_DSN",
environment=os.getenv("SENTRY_ENVIRONMENT", "development"), # ✅
release=os.getenv("SENTRY_RELEASE", "my-app@1.0.0"), # ✅
)
4.3. Ignoring Inbound Filters
If Sentry events aren't appearing, check your Sentry project's Project Settings > Inbound Filters. Ensure you haven't accidentally enabled filters that block events (e.g., "Filter out errors known to be caused by browser extensions" if you're in a shared environment).
5. Testing Approaches
5.1. Disabling Sentry in Test Environments
Prevent test noise and unnecessary Sentry events by disabling the SDK during automated tests.
✅ GOOD: Conditional Sentry Initialization
import os
import sentry_sdk
# Only initialize Sentry if DSN is present AND not in a test environment
if os.getenv("SENTRY_DSN") and os.getenv("APP_ENV") != "test":
sentry_sdk.init(
dsn=os.getenv("SENTRY_DSN"),
environment=os.getenv("SENTRY_ENVIRONMENT", "development"),
release=os.getenv("SENTRY_RELEASE", "unknown"),
traces_sample_rate=float(os.getenv("SENTRY_TRACES_SAMPLE_RATE", "0.0")),
enable_tracing=True,
)
5.2. Manual Error Capture
For specific, non-critical errors that you want to report without crashing the application, use sentry_sdk.capture_message() or sentry_sdk.capture_exception().
✅ GOOD: Manual Capture
import sentry_sdk
def process_data(data: list):
if not data:
sentry_sdk.capture_message("Received empty data for processing.", level="warning") # ✅ Report non-exception issues
return False
try:
# ... process data ...
raise ConnectionError("Database unreachable")
except ConnectionError as e:
sentry_sdk.capture_exception(e) # ✅ Explicitly capture exceptions
return False