Python - Sentry SDK
Real-time error tracking and performance monitoring for Python applications.
Python - Sentry SDK
Real-time error tracking and performance monitoring for Python applications.
Overview
Sentry is an error tracking and performance monitoring platform that helps developers identify, triage, and resolve issues in production. The Sentry Python SDK automatically captures exceptions, logs, and performance metrics, providing detailed context about errors and their impact.
flowchart LR
A[Python App] -->|Captures| B[Sentry SDK]
B -->|Sends Events| C[Sentry Server]
C -->|Stores| D[(Event Data)]
C -->|Notifies| E[Alerts]
C -->|Displays| F[Dashboard]
F -->|Analysis| G[Developers]
Installation and Setup
Installation
# Basic installation
pip install sentry-sdk
# With web framework integrations
pip install sentry-sdk[flask]
pip install sentry-sdk[django]
pip install sentry-sdk[fastapi]
# With additional features
pip install sentry-sdk[sqlalchemy]
pip install sentry-sdk[redis]
Basic Initialisation
import sentry_sdk
sentry_sdk.init(
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
# Set traces_sample_rate to 1.0 to capture 100%
# of transactions for performance monitoring.
traces_sample_rate=1.0,
# Set profiles_sample_rate to 1.0 to profile 100%
# of sampled transactions.
profiles_sample_rate=1.0,
)
Environment Configuration
import sentry_sdk
sentry_sdk.init(
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
environment="production", # e.g., "staging", "development"
release="my-app@1.0.0", # Version tracking
traces_sample_rate=0.1, # 10% of transactions
profiles_sample_rate=0.1, # 10% of profiles
# Additional options
debug=False, # Enable for debugging SDK issues
attach_stacktrace=True, # Attach stacktrace to messages
send_default_pii=False, # Don't send personally identifiable info
max_breadcrumbs=50, # Maximum breadcrumbs to store
)
Framework Integration
# Flask
from flask import Flask
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
sentry_sdk.init(
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
integrations=[FlaskIntegration()],
)
app = Flask(__name__)
# Django (in settings.py)
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
sentry_sdk.init(
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
integrations=[DjangoIntegration()],
)
# FastAPI
from fastapi import FastAPI
import sentry_sdk
from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.starlette import StarletteIntegration
sentry_sdk.init(
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
integrations=[
StarletteIntegration(),
FastApiIntegration(),
],
)
app = FastAPI()
Capturing Exceptions and Messages
Automatic Exception Capture
import sentry_sdk
sentry_sdk.init(dsn="...")
# Uncaught exceptions are automatically captured
def process_data():
result = 1 / 0 # ZeroDivisionError captured automatically
try:
process_data()
except Exception as e:
# Exception is already captured, but you can add context
sentry_sdk.capture_exception(e)
Manual Exception Capture
import sentry_sdk
try:
risky_operation()
except Exception as e:
# Capture with additional context
sentry_sdk.capture_exception(e)
# Capture current exception in except block
try:
something()
except:
sentry_sdk.capture_exception()
Logging Messages
import sentry_sdk
# Capture informational messages
sentry_sdk.capture_message("User login successful", level="info")
# Different severity levels
sentry_sdk.capture_message("Database connection slow", level="warning")
sentry_sdk.capture_message("Critical system failure", level="error")
sentry_sdk.capture_message("Security breach detected", level="fatal")
# Available levels: "debug", "info", "warning", "error", "fatal"
Breadcrumbs
import sentry_sdk
# Add breadcrumbs for context
sentry_sdk.add_breadcrumb(
category="auth",
message="User logged in",
level="info",
)
sentry_sdk.add_breadcrumb(
category="database",
message="Query executed",
level="info",
data={
"query": "SELECT * FROM users",
"duration_ms": 145,
}
)
# Breadcrumbs are automatically included with errors
try:
process_order()
except Exception:
sentry_sdk.capture_exception() # Includes all breadcrumbs
Context and User Information
Setting User Context
import sentry_sdk
# Set user information
sentry_sdk.set_user({
"id": "12345",
"email": "john.doe@example.com",
"username": "johndoe",
"ip_address": "127.0.0.1",
})
# Clear user context
sentry_sdk.set_user(None)
Adding Tags
import sentry_sdk
# Add tags for filtering and searching
sentry_sdk.set_tag("environment", "production")
sentry_sdk.set_tag("server", "web-01")
sentry_sdk.set_tag("feature_flag", "new_checkout")
# Tags help organise and filter issues in Sentry UI
Adding Extra Context
import sentry_sdk
# Add arbitrary extra data
sentry_sdk.set_context("order", {
"order_id": "ORD-123",
"total": 99.99,
"items": 3,
"payment_method": "credit_card",
})
sentry_sdk.set_context("server_info", {
"hostname": "web-01",
"region": "eu-west-1",
"instance_type": "t3.medium",
})
Scoped Context
import sentry_sdk
# Context for a specific operation (SDK v2+)
def process_user_request(user_id):
with sentry_sdk.new_scope() as scope:
scope.set_user({"id": user_id})
scope.set_tag("operation", "user_request")
scope.set_context("request_info", {
"user_id": user_id,
"timestamp": "2025-11-24T10:30:00Z",
})
# Any errors here include this context
risky_operation()
# Context is cleared after the scope
Transaction Context
import sentry_sdk
# Group related operations (SDK v2+)
scope = sentry_sdk.get_current_scope()
scope.set_transaction_name("process_payment")
# All events use this transaction name
process_payment()
validate_card()
charge_customer()
Performance Monitoring
Transaction Tracing
import sentry_sdk
# Manual transaction
with sentry_sdk.start_transaction(name="process_order", op="task") as transaction:
# Transaction automatically tracked
validate_order()
charge_payment()
send_confirmation()
Spans for Detailed Timing
import sentry_sdk
with sentry_sdk.start_transaction(name="checkout", op="http.server"):
# Add child spans for granular timing
with sentry_sdk.start_span(op="db.query", description="Load user"):
user = db.query(User).get(user_id)
with sentry_sdk.start_span(op="http.request", description="Payment API"):
response = payment_gateway.charge(user, amount)
with sentry_sdk.start_span(op="db.query", description="Save order"):
order = Order.create(user=user, total=amount)
db.session.add(order)
db.session.commit()
Automatic Performance Tracking
import sentry_sdk
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
from sentry_sdk.integrations.redis import RedisIntegration
sentry_sdk.init(
dsn="...",
traces_sample_rate=0.1,
integrations=[
SqlalchemyIntegration(), # Track database queries
RedisIntegration(), # Track Redis operations
],
)
# Database queries and Redis ops are automatically tracked
Custom Performance Metrics
import sentry_sdk
import time
def process_batch():
start_time = time.time()
with sentry_sdk.start_transaction(name="batch_process", op="task"):
# Your processing logic
for item in items:
with sentry_sdk.start_span(op="process", description="item"):
process_item(item)
duration = time.time() - start_time
sentry_sdk.set_measurement("batch_duration", duration, "second")
sentry_sdk.set_measurement("items_processed", len(items), "none")
Common Use Cases
Web Application Error Tracking
# Flask application
from flask import Flask, request
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
sentry_sdk.init(
dsn="...",
integrations=[FlaskIntegration()],
traces_sample_rate=0.1,
before_send=lambda event, hint: filter_sensitive_data(event),
)
app = Flask(__name__)
@app.before_request
def add_request_context():
sentry_sdk.set_context("request", {
"url": request.url,
"method": request.method,
"user_agent": request.user_agent.string,
})
@app.route("/api/users/<user_id>")
def get_user(user_id):
with sentry_sdk.start_transaction(name="get_user", op="http.server"):
user = User.query.get(user_id)
if not user:
sentry_sdk.capture_message(f"User {user_id} not found", level="warning")
return {"error": "Not found"}, 404
return user.to_dict()
Background Job Monitoring
import sentry_sdk
from celery import Celery
from sentry_sdk.integrations.celery import CeleryIntegration
sentry_sdk.init(
dsn="...",
integrations=[CeleryIntegration()],
traces_sample_rate=1.0,
)
app = Celery("tasks")
@app.task
def process_email_queue():
with sentry_sdk.start_transaction(name="process_email_queue", op="task"):
emails = get_pending_emails()
for email in emails:
with sentry_sdk.start_span(op="email.send", description=email.subject):
try:
send_email(email)
except Exception as e:
sentry_sdk.capture_exception(e)
sentry_sdk.set_tag("email_id", email.id)
Microservices Distributed Tracing
import sentry_sdk
import requests
sentry_sdk.init(
dsn="...",
traces_sample_rate=1.0,
)
def call_downstream_service():
with sentry_sdk.start_transaction(name="call_service", op="http.client"):
# Sentry automatically propagates trace context (SDK v2+)
headers = {
"sentry-trace": sentry_sdk.get_traceparent(),
"baggage": sentry_sdk.get_baggage(),
}
response = requests.get(
"https://api.example.com/data",
headers=headers
)
return response.json()
API Rate Limiting and Monitoring
from fastapi import FastAPI, Request
import sentry_sdk
from sentry_sdk.integrations.fastapi import FastApiIntegration
sentry_sdk.init(
dsn="...",
integrations=[FastApiIntegration()],
traces_sample_rate=0.1,
)
app = FastAPI()
@app.middleware("http")
async def track_api_usage(request: Request, call_next):
with sentry_sdk.start_transaction(
name=f"{request.method} {request.url.path}",
op="http.server"
) as transaction:
# Add request metadata
sentry_sdk.set_tag("endpoint", request.url.path)
sentry_sdk.set_tag("method", request.method)
response = await call_next(request)
# Track response status
transaction.set_status(response.status_code)
sentry_sdk.set_tag("status_code", response.status_code)
return response
Database Query Performance
import sentry_sdk
from sqlalchemy import create_engine
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
sentry_sdk.init(
dsn="...",
integrations=[SqlalchemyIntegration()],
traces_sample_rate=1.0,
)
engine = create_engine("postgresql://...")
def get_user_orders(user_id):
with sentry_sdk.start_transaction(name="get_user_orders", op="db"):
# SQLAlchemy queries are automatically tracked
with sentry_sdk.start_span(op="db.query", description="fetch user"):
user = session.query(User).get(user_id)
with sentry_sdk.start_span(op="db.query", description="fetch orders"):
orders = session.query(Order).filter_by(user_id=user_id).all()
# Track query performance
sentry_sdk.set_measurement("order_count", len(orders), "none")
return orders
Filtering and Sampling
Event Filtering
import sentry_sdk
def before_send(event, hint):
# Don't send events for specific exceptions
if "exc_info" in hint:
exc_type, exc_value, tb = hint["exc_info"]
if isinstance(exc_value, KeyboardInterrupt):
return None # Don't send
# Filter out sensitive data
if "request" in event:
event["request"].pop("cookies", None)
return event
sentry_sdk.init(
dsn="...",
before_send=before_send,
)
Sampling Configuration
import sentry_sdk
import random
def traces_sampler(sampling_context):
# Sampling based on transaction name
transaction_name = sampling_context.get("transaction_context", {}).get("name")
if transaction_name == "health_check":
return 0.0 # Never sample health checks
elif transaction_name == "critical_api":
return 1.0 # Always sample critical endpoints
else:
return 0.1 # 10% for everything else
sentry_sdk.init(
dsn="...",
traces_sampler=traces_sampler,
)
Ignoring Errors
import sentry_sdk
from sentry_sdk.integrations.logging import ignore_logger
sentry_sdk.init(
dsn="...",
ignore_errors=[
KeyboardInterrupt,
BrokenPipeError,
ConnectionResetError,
],
)
# Ignore specific loggers
ignore_logger("django.security.DisallowedHost")
ignore_logger("urllib3.connectionpool")
Quick Reference
Initialisation Options
| Option | Description | Default |
|---|---|---|
dsn |
Data Source Name (project key) | Required |
environment |
Environment name (prod, staging) | None |
release |
Version identifier | None |
traces_sample_rate |
Percentage of transactions to track | 0.0 |
profiles_sample_rate |
Percentage of profiles to capture | 0.0 |
debug |
Enable SDK debug logging | False |
attach_stacktrace |
Add stacktraces to messages | False |
send_default_pii |
Send personally identifiable info | False |
max_breadcrumbs |
Maximum breadcrumbs to store | 100 |
Common SDK Methods
# Capture events
sentry_sdk.capture_exception(exception)
sentry_sdk.capture_message(message, level="info")
# Context
sentry_sdk.set_user({"id": "123", "email": "user@example.com"})
sentry_sdk.set_tag("key", "value")
sentry_sdk.set_context("name", {"key": "value"})
sentry_sdk.add_breadcrumb(category="auth", message="Login", level="info")
# Performance
sentry_sdk.start_transaction(name="operation", op="task")
sentry_sdk.start_span(op="db.query", description="SELECT users")
# Scope management (SDK v2+)
sentry_sdk.new_scope() # fork current scope for a localised block
sentry_sdk.isolation_scope() # fork isolation scope for a full transaction
sentry_sdk.get_current_scope() # mutate scope without a context manager
Integration Packages
# Web frameworks
sentry-sdk[flask]
sentry-sdk[django]
sentry-sdk[fastapi]
sentry-sdk[starlette]
# Async/Task queues
sentry-sdk[celery]
sentry-sdk[rq]
sentry-sdk[aiohttp]
# Databases
sentry-sdk[sqlalchemy]
sentry-sdk[redis]
# Other
sentry-sdk[beam]
sentry-sdk[boto3]
sentry-sdk[pure_eval]
Common Issues and Solutions
Events Not Appearing in Sentry
Problem: Initialised Sentry but events aren't showing up in the dashboard.
# Solution 1: Check DSN is correct
import sentry_sdk
sentry_sdk.init(
dsn="https://key@o0.ingest.sentry.io/0", # Verify this is correct
debug=True, # Enable to see SDK logs
)
# Solution 2: Ensure event is being sent before app exits
import sentry_sdk
sentry_sdk.capture_message("test")
sentry_sdk.flush(timeout=2.0) # Wait for events to be sent
# Solution 3: Check network connectivity
# Sentry requires outbound HTTPS to *.ingest.sentry.io
Too Many Events / Rate Limiting
Problem: Hitting rate limits or generating too many events.
# Solution: Implement sampling and filtering
import sentry_sdk
def before_send(event, hint):
# Filter noisy errors
if "exc_info" in hint:
exc_type, exc_value, tb = hint["exc_info"]
if isinstance(exc_value, (KeyError, ValueError)):
return None
return event
sentry_sdk.init(
dsn="...",
traces_sample_rate=0.01, # Sample 1% of transactions
before_send=before_send,
ignore_errors=[KeyboardInterrupt, ConnectionError],
)
Performance Impact
Problem: Sentry SDK affecting application performance.
# Solution: Optimise sampling and async sending
import sentry_sdk
sentry_sdk.init(
dsn="...",
traces_sample_rate=0.05, # Lower sample rate
profiles_sample_rate=0.01, # Minimal profiling
max_breadcrumbs=30, # Reduce breadcrumb storage
attach_stacktrace=False, # Disable for messages
# Events are sent asynchronously by default via the built-in HttpTransport.
# Use traces_sampler / before_send for fine-grained control rather than
# a custom transport. If you do need a custom transport, subclass
# sentry_sdk.transport.HttpTransport rather than passing a lambda —
# function transports are deprecated in sentry-sdk v2 and will be removed.
)
Sensitive Data in Events
Problem: PII or secrets appearing in error reports.
# Solution: Filter data before sending
import sentry_sdk
from sentry_sdk.scrubber import EventScrubber
def before_send(event, hint):
# Remove sensitive fields
if "request" in event:
event["request"].pop("cookies", None)
event["request"].pop("headers", None)
# Scrub environment variables
if "contexts" in event and "runtime" in event["contexts"]:
event["contexts"]["runtime"].pop("environment", None)
return event
sentry_sdk.init(
dsn="...",
send_default_pii=False, # Disable PII by default
before_send=before_send,
)
Integration Not Working
Problem: Framework integration not capturing errors automatically.
# Solution: Verify integration is loaded correctly
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
# Check integration is in list
sentry_sdk.init(
dsn="...",
integrations=[
FlaskIntegration(), # Must be initialised
],
debug=True, # Check logs for integration messages
)
# For Django, ensure in settings.py, not views.py
# For FastAPI, ensure both Starlette and FastAPI integrations
Grouping Issues
Problem: Similar errors creating separate issues in Sentry.
# Solution: Customise fingerprinting
import sentry_sdk
def before_send(event, hint):
# Custom grouping logic
if "exception" in event:
exc = event["exception"]["values"][0]
# Group by exception type and first line of stacktrace
if exc.get("stacktrace", {}).get("frames"):
frame = exc["stacktrace"]["frames"][-1]
event["fingerprint"] = [
exc["type"],
frame.get("function", "unknown"),
]
return event
sentry_sdk.init(
dsn="...",
before_send=before_send,
)
Source Maps for Minified Code
Problem: Stacktraces showing minified/compiled code locations.
# Solution: Upload source maps (for Python, ensure frames have correct paths)
# Ensure release is set and matches deployment
import sentry_sdk
sentry_sdk.init(
dsn="...",
release="my-app@1.2.3", # Must match source map upload
environment="production",
)
Transaction Name Explosion
Problem: Too many unique transaction names (e.g., with IDs in path).
# Solution: Parameterise transaction names
from flask import Flask, request
import sentry_sdk
app = Flask(__name__)
@app.before_request
def set_transaction_name():
# Use route pattern, not actual URL with IDs
if request.url_rule:
sentry_sdk.set_tag("transaction", request.url_rule.rule)
# Or for manual transactions
with sentry_sdk.start_transaction(
name="/api/users/{user_id}", # Parameterised
op="http.server"
):
process_user(user_id)