OpenTelemetry SQLAlchemy Instrumentation
This library provides OpenTelemetry instrumentation for the SQLAlchemy Python library, allowing automatic tracing of database queries. It captures SQL statements, execution time, and connection information, providing insights into database operations within your application's distributed traces. Part of the `opentelemetry-python-contrib` project, it is currently in beta with frequent releases, often on a monthly cadence, aligning with the broader OpenTelemetry Python project.
Warnings
- gotcha This library is currently in beta (indicated by `b0` in the version number). While widely used, its API is not yet guaranteed to be stable, and breaking changes may occur in minor or patch releases leading up to a stable 1.0 version.
- breaking The inclusion of `sqlcomment` (trace context) in the `db.statement` span attribute became opt-in. By default, full SQL statements with comments may not appear in your traces unless explicitly configured. This change was likely made for security/privacy considerations.
- gotcha Instrumentation must be enabled *before* SQLAlchemy engines or sessions are created. If an engine or session already exists when `instrument()` is called, its operations might not be captured.
- gotcha When using `opentelemetry-instrumentation-sqlalchemy`, do not install separate OpenTelemetry instrumentation packages for the underlying database drivers (e.g., `opentelemetry-instrumentation-psycopg2` for PostgreSQL or `opentelemetry-instrumentation-sqlite3`). Doing so can lead to duplicate spans or unexpected behavior.
- gotcha The instrumentation was primarily designed for synchronous SQLAlchemy. When using SQLAlchemy's async engines (e.g., `create_async_engine`), spans might not be fully or correctly captured due to differences in how event hooks fire in an async context.
Install
-
pip install opentelemetry-instrumentation-sqlalchemy -
pip install opentelemetry-sdk opentelemetry-exporter-otlp sqlalchemy
Imports
- SQLAlchemyInstrumentor
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
Quickstart
import os
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
from sqlalchemy import create_engine, text
# Configure OpenTelemetry Tracer Provider
resource = Resource.create({"service.name": os.environ.get("OTEL_SERVICE_NAME", "sqlalchemy-app")})
tracer_provider = TracerProvider(resource=resource)
tracer_provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(tracer_provider)
# Instrument SQLAlchemy
# For global instrumentation of all engines, call without 'engine' argument:
# SQLAlchemyInstrumentor().instrument()
# For specific engine instrumentation:
engine = create_engine("sqlite:///:memory:")
SQLAlchemyInstrumentor().instrument(engine=engine)
# Use SQLAlchemy
with engine.connect() as connection:
connection.execute(text("CREATE TABLE users (id INTEGER, name TEXT)"))
connection.execute(text("INSERT INTO users (id, name) VALUES (1, 'Alice')"))
connection.execute(text("INSERT INTO users (id, name) VALUES (2, 'Bob')"))
connection.commit()
result = connection.execute(text("SELECT * FROM users WHERE id = 1"))
for row in result:
print(f"User: {row.name}")
SQLAlchemyInstrumentor().uninstrument()
print("SQLAlchemy instrumentation demonstration complete.")