Sentry instrumentation for pyodbc database calls
Project description
sentry-pyodbc
Sentry instrumentation for pyodbc database calls. Provides automatic performance spans and breadcrumbs for Microsoft SQL Server database operations, similar to Sentry's SQLAlchemy integration but for raw DB-API usage with pyodbc.
Features
- Automatic instrumentation: Drop-in replacement for
pyodbc.connect()with Sentry spans and breadcrumbs - Safe by default: Never captures parameter values or credentials
- Configurable: Fine-tune what gets traced and how
- Monkeypatch mode: Globally instrument all
pyodbc.connect()calls - Minimal overhead: Only instruments when Sentry SDK is initialized
Installation
pip install sentry-pyodbc
Or with uv:
uv add sentry-pyodbc
Quickstart
Basic Usage
Use sentry_pyodbc.connect() as a drop-in replacement for pyodbc.connect():
import sentry_sdk
import sentry_pyodbc
sentry_sdk.init(dsn="YOUR_SENTRY_DSN")
# Use sentry_pyodbc.connect() instead of pyodbc.connect()
conn = sentry_pyodbc.connect(
"DRIVER={ODBC Driver 17 for SQL Server};"
"SERVER=localhost;"
"DATABASE=mydb;"
"UID=myuser;"
"PWD=mypassword"
)
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE id = ?", (1,))
results = cursor.fetchall()
conn.commit()
Monkeypatch Mode
For global instrumentation without changing existing code:
import sentry_sdk
import sentry_pyodbc
sentry_sdk.init(dsn="YOUR_SENTRY_DSN")
# Monkeypatch pyodbc.connect globally
sentry_pyodbc.instrument_pyodbc()
# Now all pyodbc.connect() calls are automatically instrumented
import pyodbc
conn = pyodbc.connect("...") # Automatically instrumented!
Safety & Privacy
This package is designed with security and privacy in mind:
- ✅ Never captures parameter values - Only SQL structure is logged
- ✅ SQL sanitization - Literals are replaced with
?placeholders - ✅ No credential extraction - Connection strings are parsed but passwords are never stored
- ✅ Safe defaults - All potentially sensitive features are opt-in
Configuration
Create a Config instance to customize behavior:
from sentry_pyodbc import Config, connect
config = Config(
add_spans=True, # Create performance spans (default: True)
add_breadcrumbs=True, # Create breadcrumbs (default: True)
trace_fetch=False, # Trace fetch operations (default: False)
trace_commit_rollback=False, # Trace commit/rollback (default: False)
sanitize_sql=True, # Replace literals with ? (default: True)
max_sql_length=1000, # Truncate SQL at this length (default: 1000)
)
conn = connect("...", config=config)
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
add_breadcrumbs |
bool |
True |
Create Sentry breadcrumbs for queries |
add_spans |
bool |
True |
Create Sentry performance spans |
span_op |
str |
"db" |
Operation name for spans |
span_description_strategy |
"sanitized_sql" | "operation_only" |
"sanitized_sql" |
What to use as span description |
breadcrumb_message_strategy |
"sanitized_sql" | "operation_only" |
"operation_only" |
What to use as breadcrumb message |
max_sql_length |
int |
1000 |
Maximum SQL length before truncation |
sanitize_sql |
bool |
True |
Replace literals with ? placeholders |
trace_fetch |
bool |
False |
Create spans for fetch operations |
trace_commit_rollback |
bool |
False |
Create spans for commit/rollback |
db_system_tag |
str |
"mssql" |
Database system tag for spans |
set_data_db |
bool |
False |
Use set_data() instead of tags for DB metadata |
extract_connect_target |
bool |
True |
Extract server/database from connection string |
record_driver |
bool |
False |
Record ODBC driver information |
cursor_methods_to_trace |
tuple[str, ...] |
("execute", "executemany") |
Methods to instrument |
sql_sanitizer |
Callable[[str], str] | None |
None |
Custom SQL sanitization function |
sql_classifier |
Callable[[str], str] | None |
None |
Custom SQL classification function |
Integration Examples
FastAPI
from fastapi import FastAPI
import sentry_sdk
import sentry_pyodbc
sentry_sdk.init(dsn="YOUR_SENTRY_DSN")
sentry_pyodbc.instrument_pyodbc() # Global instrumentation
app = FastAPI()
@app.get("/users")
def get_users():
import pyodbc
conn = pyodbc.connect("...") # Automatically instrumented
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
return cursor.fetchall()
Django
# In your Django settings.py or startup code
import sentry_sdk
import sentry_pyodbc
sentry_sdk.init(dsn="YOUR_SENTRY_DSN")
sentry_pyodbc.instrument_pyodbc()
Celery
# In your Celery app initialization
from celery import Celery
import sentry_sdk
import sentry_pyodbc
sentry_sdk.init(dsn="YOUR_SENTRY_DSN")
sentry_pyodbc.instrument_pyodbc()
app = Celery("myapp")
What Gets Traced
By default, the following operations create spans and breadcrumbs:
cursor.execute(sql, *params)- SQL executioncursor.executemany(sql, *params)- Bulk SQL execution
Optional (disabled by default):
cursor.fetchone(),fetchall(),fetchmany()- Result fetchingconnection.commit(),rollback()- Transaction operations
SQL Sanitization
SQL statements are automatically sanitized before being sent to Sentry:
- Quoted strings are replaced with
? - Numeric literals are replaced with
? - Whitespace is normalized
- SQL is truncated at
max_sql_length
Example:
-- Original
SELECT * FROM users WHERE name = 'John' AND age = 25
-- Sanitized
SELECT * FROM users WHERE name = ? AND age = ?
Testing
Run tests with pytest:
# Install dev dependencies
uv sync --dev
# Run all tests
uv run pytest
# Run without integration tests
uv run pytest -m "not integration"
# Run with coverage
uv run pytest --cov=sentry_pyodbc --cov-report=html
Development
Setup
# Clone the repository
git clone https://github.com/yourusername/sentry-pyodbc.git
cd sentry-pyodbc
# Install with uv
uv sync --dev
# Run linting
uv run ruff check .
uv run mypy sentry_pyodbc
# Run tests
uv run pytest
Code Quality
This project uses:
rufffor lintingmypyfor type checkingpytestfor testing
License
MIT License - see LICENSE file for details.
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
Release Process
See RELEASING.md for instructions on how to release a new version.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sentry_pyodbc-0.1.0.tar.gz.
File metadata
- Download URL: sentry_pyodbc-0.1.0.tar.gz
- Upload date:
- Size: 96.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4760f0a2c72a6eb05e1423b7df971a46a8a1210db0f8900cdf756d912a6397f5
|
|
| MD5 |
2ce8fe30a8c3c114b8e6b34d28929d38
|
|
| BLAKE2b-256 |
cb13ea7bfbcc72fc99f4c600d75588db17319857a453a9fffd97c43e18299b94
|
File details
Details for the file sentry_pyodbc-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sentry_pyodbc-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c733159fc82ddbd5bc8ccdaf275adff6c503216b1b1b5353383520928a3a78b
|
|
| MD5 |
9d1deccf32449f29cc41a8b4506bf92b
|
|
| BLAKE2b-256 |
f910f3302dfe3faaf2c4df7bd89e06e14a7074614279bb14ed8ed75346afc027
|