Skip to content

opentelemetry-instrumentation-pymssql: OTEL_SEMCONV_STABILITY_OPT_IN partially ineffective for host/port/user attributes #4591

Description

@luke6Lh43

Describe your environment

What happened?

I was testing the recent implementation of stable semantic conventions for MSSQL (PR #4109) and found that OTEL_SEMCONV_STABILITY_OPT_IN is only partially effective for pymssql. The core db.* attributes (db.system.name, db.namespace, db.query.text) migrate correctly, but net.peer.name, net.peer.port, and db.user remain hardcoded as legacy keys regardless of the opt-in setting.

The root cause is that _PyMSSQLDatabaseApiIntegration.wrapped_connection() sets these attributes using hardcoded legacy keys, bypassing the semconv-aware helper functions introduced in #4109:

self.span_attributes["db.user"] = user
self.span_attributes["net.peer.name"] = host
self.span_attributes["net.peer.port"] = port

I did some research and it seems unlike other DB-API instrumentors (pymysql, psycopg2, etc.) that rely on the standard connection_attributes mapping, pymssql cannot read connection attributes from the connection object. Instead, it overrides wrapped_connection() to extract attributes from the connect() method arguments — but this override was not updated to use the semconv helpers.

For comparison, pymysql and psycopg2 emit fully correct stable attributes under the same configuration.

Steps to Reproduce

  1. Install from main (post-DB semantic convention stability migration for DB-API and 7 inheriting db client instrumentors #4109 merge):
pip install --no-deps opentelemetry-instrumentation@git+https://github.com/open-telemetry/opentelemetry-python-contrib.git@main#subdirectory=opentelemetry-instrumentation
pip install --no-deps opentelemetry-instrumentation-dbapi@git+https://github.com/open-telemetry/opentelemetry-python-contrib.git@main#subdirectory=instrumentation/opentelemetry-instrumentation-dbapi
pip install --no-deps opentelemetry-instrumentation-pymssql@git+https://github.com/open-telemetry/opentelemetry-python-contrib.git@main#subdirectory=instrumentation/opentelemetry-instrumentation-pymssql
  1. Run a simple app with auto-instrumentation:
import pymssql
conn = pymssql.connect(server="localhost", port=1433, user="sa", password="YourStrong!Passw0rd", database="master")
cursor = conn.cursor()
cursor.execute("SELECT @@VERSION")
cursor.close()
conn.close()
  1. Execute with stable opt-in:
OTEL_SEMCONV_STABILITY_OPT_IN=database,http \
opentelemetry-instrument --traces_exporter console python app.py

Expected Result

With OTEL_SEMCONV_STABILITY_OPT_IN=database,http, spans should contain only stable attributes:

{
    "db.system.name": "mssql",
    "db.namespace": "master",
    "db.query.text": "SELECT @@VERSION",
    "server.address": "localhost",
    "server.port": 1433,
    "db.protocol.tds.version": "7.0"
}

No legacy attributes (db.user, net.peer.name, net.peer.port) should be present — matching the behavior of pymysql and psycopg2.

Actual Result

Spans contain a mix of stable and legacy attributes:

{
    "db.system.name": "mssql",
    "db.namespace": "master",
    "db.query.text": "SELECT @@VERSION",
    "db.user": "sa",
    "net.peer.name": "localhost",
    "net.peer.port": 1433,
    "db.protocol.tds.version": "7.0"
}

server.address and server.port are absent. db.user, net.peer.name, and net.peer.port are still present despite opting into stable conventions.

Additional context

The fix is straightforward — replace hardcoded attribute keys in wrapped_connection() with the semconv-aware helpers:

_set_db_user(self.span_attributes, user, self._sem_conv_opt_in_mode_db)
_set_http_net_peer_name_client(self.span_attributes, host, self._sem_conv_opt_in_mode_http)
_set_http_peer_port_client(self.span_attributes, port, self._sem_conv_opt_in_mode_http)

I have a fix ready with tests passing and will open a PR shortly.

Related:


Additional observation: The stable db.system.name value is emitted as "mssql" but per the SQL Server semantic conventions, it MUST be "microsoft.sql_server". This appears to be an issue in the base dbapi layer's _set_db_system helper which passes through the raw value without mapping. This likely affects all DB instrumentors and may warrant a separate fix.

Would you like to implement a fix?

Yes

Tip

React with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1 or me too, to help us triage it. Learn more here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions