Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
df17c09
Add _semconv set_db fns
tammy-baylis-swi Jan 20, 2026
c41c5b2
lint
tammy-baylis-swi Jan 20, 2026
d067840
Changelog
tammy-baylis-swi Jan 20, 2026
8b78135
semconv opt-in for sqlalchemy instr
tammy-baylis-swi Jan 21, 2026
7e4c458
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Jan 22, 2026
2a6c066
use imports not hardcode
tammy-baylis-swi Jan 22, 2026
3598cfc
Update comment on comment-in-attr
tammy-baylis-swi Jan 22, 2026
f830a0f
Add tests
tammy-baylis-swi Jan 22, 2026
575772a
Changelog
tammy-baylis-swi Jan 22, 2026
b03fb67
Add migration status
tammy-baylis-swi Jan 23, 2026
1340532
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Jan 23, 2026
7d46aea
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Jan 26, 2026
653a1e3
Sqlalchemy http,database opt-in
tammy-baylis-swi Jan 26, 2026
50eb085
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Jan 27, 2026
36e487a
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Feb 9, 2026
b9ef17a
meter schema_url
tammy-baylis-swi Feb 9, 2026
66e0dbd
Add sqlalchemy _get_db_name_from_cursor
tammy-baylis-swi Feb 10, 2026
5477ff8
Add per-signal semconv opt-in schema url precedence; add sqlalchemy u…
tammy-baylis-swi Feb 11, 2026
75f83d5
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Feb 17, 2026
903e1f8
Update _get_db_name coverage
tammy-baylis-swi Feb 18, 2026
a845a1b
More db_name_from_cursor cases
tammy-baylis-swi Feb 18, 2026
5986c87
split to lint
tammy-baylis-swi Feb 18, 2026
c74d7ca
_get_schema parses url from semconv
tammy-baylis-swi Feb 24, 2026
e15fe2a
_get_* from cursor or conn
tammy-baylis-swi Feb 24, 2026
b4ab9a4
Add _semconv set_db_operation, used by sqlalchemy
tammy-baylis-swi Feb 24, 2026
86c7e75
get_db_name safer, update docker-test
tammy-baylis-swi Feb 24, 2026
30b15b3
Fix test
tammy-baylis-swi Feb 24, 2026
8feba0b
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Feb 24, 2026
dcd285e
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Feb 26, 2026
e9f87cc
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Mar 3, 2026
b3ab25f
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Mar 5, 2026
4ca2e48
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Mar 19, 2026
6271c0d
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Mar 25, 2026
04de712
Add schema_url asserts
tammy-baylis-swi Mar 26, 2026
a1daea9
Merge branch 'main' into sqlalchemy-semconv-opt-in
tammy-baylis-swi Mar 27, 2026
0f78666
Update CHANGELOG.md
xrmx Apr 1, 2026
6ac869d
Merge branch 'main' into sqlalchemy-semconv-opt-in
xrmx Apr 1, 2026
ca0eb45
Merge branch 'main' into sqlalchemy-semconv-opt-in
xrmx Apr 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#3993](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3993))
- `opentelemetry-instrumentation-pyramid` Implement new semantic convention opt-in migration
([#3982](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3982))
- `opentelemetry-instrumentation-sqlalchemy`: implement new semantic convention opt-in migration
([#4110](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/4110))

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion instrumentation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
| [opentelemetry-instrumentation-redis](./opentelemetry-instrumentation-redis) | redis >= 2.6 | No | development
| [opentelemetry-instrumentation-remoulade](./opentelemetry-instrumentation-remoulade) | remoulade >= 0.50 | No | development
| [opentelemetry-instrumentation-requests](./opentelemetry-instrumentation-requests) | requests ~= 2.0 | Yes | migration
| [opentelemetry-instrumentation-sqlalchemy](./opentelemetry-instrumentation-sqlalchemy) | sqlalchemy >= 1.0.0, < 2.1.0 | Yes | development
| [opentelemetry-instrumentation-sqlalchemy](./opentelemetry-instrumentation-sqlalchemy) | sqlalchemy >= 1.0.0, < 2.1.0 | Yes | migration
| [opentelemetry-instrumentation-sqlite3](./opentelemetry-instrumentation-sqlite3) | sqlite3 | No | development
| [opentelemetry-instrumentation-starlette](./opentelemetry-instrumentation-starlette) | starlette >= 0.13 | Yes | development
| [opentelemetry-instrumentation-system-metrics](./opentelemetry-instrumentation-system-metrics) | psutil >= 5 | No | development
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,24 +110,24 @@
SQLComment in span attribute
****************************
If sqlcommenter is enabled, you can opt into the inclusion of sqlcomment in
the query span ``db.statement`` attribute for your needs. If ``commenter_options``
have been set, the span attribute comment will also be configured by this
setting.
the query span ``db.statement`` and/or ``db.query.text`` attribute for your
needs. If ``commenter_options`` have been set, the span attribute comment
will also be configured by this setting.

.. code:: python

from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor

# Opts into sqlcomment for SQLAlchemy trace integration.
# Opts into sqlcomment for `db.statement` span attribute.
# Opts into sqlcomment for `db.statement` and/or `db.query.text` span attribute.
SQLAlchemyInstrumentor().instrument(
enable_commenter=True,
commenter_options={},
enable_attribute_commenter=True,
)

Warning:
Capture of sqlcomment in ``db.statement`` may have high cardinality without platform normalization. See `Semantic Conventions for database spans <https://opentelemetry.io/docs/specs/semconv/database/database-spans/#generating-a-summary-of-the-query-text>`_ for more information.
Capture of sqlcomment in ``db.statement``/``db.query.text`` may have high cardinality without platform normalization. See `Semantic Conventions for database spans <https://opentelemetry.io/docs/specs/semconv/database/database-spans/#generating-a-summary-of-the-query-text>`_ for more information.

API
---
Expand All @@ -141,6 +141,11 @@
from sqlalchemy.engine.base import Engine
from wrapt import wrap_function_wrapper as _w

from opentelemetry.instrumentation._semconv import (
_get_schema_url,
_OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType,
)
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
from opentelemetry.instrumentation.sqlalchemy.engine import (
EngineTracer,
Expand Down Expand Up @@ -181,12 +186,18 @@ def _instrument(self, **kwargs):
Returns:
An instrumented engine if passed in as an argument or list of instrumented engines, None otherwise.
"""
# Initialize semantic conventions opt-in if needed
_OpenTelemetrySemanticConventionStability._initialize()
sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
_OpenTelemetryStabilitySignalType.DATABASE,
)

tracer_provider = kwargs.get("tracer_provider")
tracer = get_tracer(
__name__,
__version__,
tracer_provider,
schema_url="https://opentelemetry.io/schemas/1.11.0",
schema_url=_get_schema_url(sem_conv_opt_in_mode),
Comment thread
tammy-baylis-swi marked this conversation as resolved.
Outdated
)

meter_provider = kwargs.get("meter_provider")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,31 @@
)

from opentelemetry import trace
from opentelemetry.instrumentation._semconv import (
_OpenTelemetrySemanticConventionStability,
_OpenTelemetryStabilitySignalType,
_set_db_name,
_set_db_statement,
_set_db_system,
_set_db_user,
_set_http_net_peer_name_client,
_set_http_peer_port_client,
)
from opentelemetry.instrumentation.sqlcommenter_utils import _add_sql_comment
from opentelemetry.instrumentation.utils import (
_get_opentelemetry_values,
is_instrumentation_enabled,
)
from opentelemetry.semconv._incubating.attributes.db_attributes import (
DB_NAME,
DB_STATEMENT,
DB_SYSTEM,
DB_USER,
)
from opentelemetry.semconv._incubating.attributes.net_attributes import (
NET_PEER_NAME,
NET_PEER_PORT,
NET_TRANSPORT,
NetTransportValues,
)
from opentelemetry.semconv.attributes.db_attributes import (
DB_NAMESPACE,
)
from opentelemetry.trace.status import Status, StatusCode


Expand Down Expand Up @@ -119,13 +127,23 @@ def _wrap_connect_internal(func, module, args, kwargs):
if not is_instrumentation_enabled():
return func(*args, **kwargs)

# Initialize semantic conventions opt-in if needed
_OpenTelemetrySemanticConventionStability._initialize()
sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
Comment thread
tammy-baylis-swi marked this conversation as resolved.
Outdated
_OpenTelemetryStabilitySignalType.DATABASE,
)

with tracer.start_as_current_span(
"connect", kind=trace.SpanKind.CLIENT
) as span:
if span.is_recording():
attrs, _ = _get_attributes_from_url(module.url)
attrs, _ = _get_attributes_from_url(
module.url, sem_conv_opt_in_mode
)
_set_db_system(
attrs, _normalize_vendor(module.name), sem_conv_opt_in_mode
)
span.set_attributes(attrs)
span.set_attribute(DB_SYSTEM, _normalize_vendor(module.name))
return func(*args, **kwargs)

return _wrap_connect_internal
Expand All @@ -143,6 +161,12 @@ def __init__(
commenter_options=None,
enable_attribute_commenter=False,
):
# Initialize semantic conventions opt-in if needed
_OpenTelemetrySemanticConventionStability._initialize()
self._sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability._get_opentelemetry_stability_opt_in_mode(
Comment thread
tammy-baylis-swi marked this conversation as resolved.
Outdated
_OpenTelemetryStabilitySignalType.DATABASE,
)

self.tracer = tracer
self.connections_usage = connections_usage
self.vendor = _normalize_vendor(engine.name)
Expand Down Expand Up @@ -278,9 +302,10 @@ def _get_commenter_data(self, conn) -> dict:

def _set_db_client_span_attributes(self, span, statement, attrs) -> None:
"""Uses statement and attrs to set attributes of provided Otel span"""
span.set_attribute(DB_STATEMENT, statement)
span.set_attribute(DB_SYSTEM, self.vendor)
for key, value in attrs.items():
span_attrs = dict(attrs)
Comment thread
tammy-baylis-swi marked this conversation as resolved.
_set_db_statement(span_attrs, statement, self._sem_conv_opt_in_mode)
_set_db_system(span_attrs, self.vendor, self._sem_conv_opt_in_mode)
for key, value in span_attrs.items():
span.set_attribute(key, value)

def _before_cur_exec(
Expand All @@ -289,11 +314,18 @@ def _before_cur_exec(
if not is_instrumentation_enabled():
return statement, params

attrs, found = _get_attributes_from_url(conn.engine.url)
attrs, found = _get_attributes_from_url(
conn.engine.url, self._sem_conv_opt_in_mode
)
if not found:
attrs = _get_attributes_from_cursor(self.vendor, cursor, attrs)
attrs = _get_attributes_from_cursor(
self.vendor, cursor, attrs, self._sem_conv_opt_in_mode
)

# Extract db_name for operation name
# Prefer old semconv (db.name) over new semconv (db.namespace) for backwards compatibility
db_name = attrs.get(DB_NAME) or attrs.get(DB_NAMESPACE) or ""
Comment thread
tammy-baylis-swi marked this conversation as resolved.
Outdated

db_name = attrs.get(DB_NAME, "")
span = self.tracer.start_span(
self._operation_name(db_name, statement),
kind=trace.SpanKind.CLIENT,
Expand All @@ -307,7 +339,7 @@ def _before_cur_exec(
# just to handle type safety
statement = str(statement)

# sqlcomment is added to executed query and db.statement span attribute
# sqlcomment is added to executed query and db.statement and/or db.query.text span attribute
statement = _add_sql_comment(
statement, **commenter_data
)
Expand All @@ -317,7 +349,7 @@ def _before_cur_exec(

else:
# sqlcomment is only added to executed query
# so db.statement is set before add_sql_comment
# so db.statement and/or db.query.text is set before add_sql_comment
self._set_db_client_span_attributes(
span, statement, attrs
)
Expand Down Expand Up @@ -358,42 +390,48 @@ def _handle_error(context):
span.end()


def _get_attributes_from_url(url):
def _get_attributes_from_url(url, sem_conv_opt_in_mode):
"""Set connection tags from the url. return true if successful."""
attrs = {}
if url.host:
attrs[NET_PEER_NAME] = url.host
_set_http_net_peer_name_client(attrs, url.host, sem_conv_opt_in_mode)
if url.port:
attrs[NET_PEER_PORT] = url.port
_set_http_peer_port_client(attrs, url.port, sem_conv_opt_in_mode)
if url.database:
attrs[DB_NAME] = url.database
_set_db_name(attrs, url.database, sem_conv_opt_in_mode)
if url.username:
attrs[DB_USER] = url.username
_set_db_user(attrs, url.username, sem_conv_opt_in_mode)
return attrs, bool(url.host)


def _get_attributes_from_cursor(vendor, cursor, attrs):
def _get_attributes_from_cursor(vendor, cursor, attrs, sem_conv_opt_in_mode):
"""Attempt to set db connection attributes by introspecting the cursor."""
if vendor == "postgresql":
info = getattr(getattr(cursor, "connection", None), "info", None)
if not info:
return attrs

attrs[DB_NAME] = info.dbname
_set_db_name(attrs, info.dbname, sem_conv_opt_in_mode)
is_unix_socket = info.host and info.host.startswith("/")

if is_unix_socket:
attrs[NET_TRANSPORT] = NetTransportValues.OTHER.value
if info.port:
# postgresql enforces this pattern on all socket names
attrs[NET_PEER_NAME] = os.path.join(
info.host, f".s.PGSQL.{info.port}"
_set_http_net_peer_name_client(
attrs,
os.path.join(info.host, f".s.PGSQL.{info.port}"),
sem_conv_opt_in_mode,
)
else:
attrs[NET_TRANSPORT] = NetTransportValues.IP_TCP.value
attrs[NET_PEER_NAME] = info.host
_set_http_net_peer_name_client(
attrs, info.host, sem_conv_opt_in_mode
)
if info.port:
attrs[NET_PEER_PORT] = int(info.port)
_set_http_peer_port_client(
attrs, int(info.port), sem_conv_opt_in_mode
)
return attrs


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@
_instruments = ("sqlalchemy >= 1.0.0, < 2.1.0",)

_supports_metrics = True

_semconv_status = "migration"
Loading