Skip to main content

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 execution
  • cursor.executemany(sql, *params) - Bulk SQL execution

Optional (disabled by default):

  • cursor.fetchone(), fetchall(), fetchmany() - Result fetching
  • connection.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:

  • ruff for linting
  • mypy for type checking
  • pytest for 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sentry_pyodbc-0.1.1.tar.gz (96.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sentry_pyodbc-0.1.1-py3-none-any.whl (11.2 kB view details)

Uploaded Python 3

File details

Details for the file sentry_pyodbc-0.1.1.tar.gz.

File metadata

  • Download URL: sentry_pyodbc-0.1.1.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

Hashes for sentry_pyodbc-0.1.1.tar.gz
Algorithm Hash digest
SHA256 601ba65575137227675e880aeaccfbe6955e1e500dbabfa5fa8516986358f85a
MD5 ed88b8dd30b5f2dc9ea53a4dbd9f7253
BLAKE2b-256 5b260ce7258d25bdc14b764cc4e9f784da3f6cbfafddac32d402267b2be6c7b1

See more details on using hashes here.

File details

Details for the file sentry_pyodbc-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: sentry_pyodbc-0.1.1-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

Hashes for sentry_pyodbc-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 552a15bfc7efaa34e128cfe231e266e1b9e20370f9153589cfebdfd4e7b7d488
MD5 dc1bd0193da4ddd5393955dcf1392150
BLAKE2b-256 83e19abd486f360a7b06279a69c921150b032335d6dedc5ebec9657bd19c8e6a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page