From b726639ed5ceae1a8e8be49e5e95ebc47f143c88 Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Thu, 10 Sep 2026 10:30:26 -0700 Subject: [PATCH 01/11] Update database semantic conventions --- .../CHANGELOG.md | 6 ++++++ .../exporter/export/trace/_exporter.py | 19 ++++++++++++++++--- .../exporter/export/trace/_utils.py | 10 ++++++++-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md index b408f3b9d37c..91cd671e79bc 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md @@ -7,6 +7,12 @@ ### Breaking Changes ### Bugs Fixed +- Recognize the new stable OpenTelemetry database semantic conventions + (`db.system.name`, `db.query.text`, `db.operation.name`, `db.namespace`) when + mapping `CLIENT` spans to `RemoteDependencyData`. Previously only the + deprecated attributes (`db.system`, `db.statement`, `db.operation`, `db.name`) + were recognized, causing dependency `Type` to be reported as `N/A` for spans + emitted with the newer conventions. ### Other Changes diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py index 651f618a9a93..7b94a2fc3a3e 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py @@ -8,6 +8,11 @@ from urllib.parse import urlparse from opentelemetry.semconv.attributes.client_attributes import CLIENT_ADDRESS +from opentelemetry.semconv.attributes.db_attributes import ( + DB_OPERATION_NAME, + DB_QUERY_TEXT, + DB_SYSTEM_NAME, +) from opentelemetry.semconv.attributes.http_attributes import ( HTTP_REQUEST_METHOD, HTTP_RESPONSE_STATUS_CODE, @@ -420,8 +425,11 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem: else: status_code = 0 data.result_code = str(status_code) - elif SpanAttributes.DB_SYSTEM in span.attributes: # Database - db_system = span.attributes[SpanAttributes.DB_SYSTEM] + elif DB_SYSTEM_NAME in span.attributes or SpanAttributes.DB_SYSTEM in span.attributes: # Database + # Prefer the new stable `db.system.name`, fall back to the deprecated `db.system`. + print("Span attributes", span.attributes) + db_system = span.attributes.get(DB_SYSTEM_NAME) or span.attributes.get(SpanAttributes.DB_SYSTEM) + print(db_system) if db_system == DbSystemValues.MYSQL.value: data.type = "mysql" elif db_system == DbSystemValues.POSTGRESQL.value: @@ -435,8 +443,13 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem: else: data.type = db_system # data is the full statement or operation - if SpanAttributes.DB_STATEMENT in span.attributes: + # Prefer new `db.query.text` / `db.operation.name`, fall back to deprecated `db.statement` / `db.operation`. + if DB_QUERY_TEXT in span.attributes: + data.data = span.attributes[DB_QUERY_TEXT] + elif SpanAttributes.DB_STATEMENT in span.attributes: data.data = span.attributes[SpanAttributes.DB_STATEMENT] + elif DB_OPERATION_NAME in span.attributes: + data.data = span.attributes[DB_OPERATION_NAME] elif SpanAttributes.DB_OPERATION in span.attributes: data.data = span.attributes[SpanAttributes.DB_OPERATION] # db specific logic for target diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py index e560376e73d1..de663c0ece26 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py @@ -7,6 +7,7 @@ from opentelemetry.semconv.attributes import ( client_attributes, + db_attributes, server_attributes, url_attributes, user_agent_attributes, @@ -159,8 +160,12 @@ def _get_target_for_dependency_from_peer(attributes: Attributes) -> Optional[str port = attributes[SpanAttributes.NET_PEER_PORT] # TODO: check default port for rpc # This logic assumes default ports never conflict across dependency types + # Honor both the new stable `db.system.name` and the deprecated `db.system`. + db_system_for_port = attributes.get(db_attributes.DB_SYSTEM_NAME) or attributes.get( + SpanAttributes.DB_SYSTEM + ) if port != _get_default_port_http(attributes) and port != _get_default_port_db( - str(attributes.get(SpanAttributes.DB_SYSTEM)) + str(db_system_for_port) ): target = "{}:{}".format(target, port) return target @@ -231,7 +236,8 @@ def _get_target_for_db_dependency( attributes: Attributes, ) -> Optional[str]: if attributes: - db_name = attributes.get(SpanAttributes.DB_NAME) + # Prefer new stable `db.namespace`, fall back to deprecated `db.name`. + db_name = attributes.get(db_attributes.DB_NAMESPACE) or attributes.get(SpanAttributes.DB_NAME) if db_name: if not target: target = str(db_name) From 4954fa0f833d1758fa2346b81a933cccbe7dc5c3 Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Fri, 11 Sep 2026 09:07:06 -0700 Subject: [PATCH 02/11] Update database semantic conventions for quickpulse and added test coverage --- .../exporter/_quickpulse/_types.py | 15 ++++++++--- .../exporter/export/trace/_exporter.py | 2 -- .../exporter/export/trace/_utils.py | 4 +-- .../tests/quickpulse/test_types.py | 26 +++++++++++++++++++ .../tests/trace/test_trace.py | 20 +++++++++++++- 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_quickpulse/_types.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_quickpulse/_types.py index bac39d33976c..2f95780b0354 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_quickpulse/_types.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_quickpulse/_types.py @@ -7,6 +7,11 @@ from opentelemetry._logs import LogRecord from opentelemetry.sdk.trace import ReadableSpan from opentelemetry.semconv._incubating.attributes import gen_ai_attributes +from opentelemetry.semconv.attributes.db_attributes import ( + DB_OPERATION_NAME, + DB_QUERY_TEXT, + DB_SYSTEM_NAME, +) from opentelemetry.semconv.attributes.http_attributes import ( HTTP_REQUEST_METHOD, HTTP_RESPONSE_STATUS_CODE, @@ -114,16 +119,20 @@ def _from_span(span: ReadableSpan): url, ) data = url - elif SpanAttributes.DB_SYSTEM in attributes: - db_system = attributes[SpanAttributes.DB_SYSTEM] + elif DB_SYSTEM_NAME in attributes or SpanAttributes.DB_SYSTEM in attributes: + db_system = attributes.get(DB_SYSTEM_NAME) or attributes.get(SpanAttributes.DB_SYSTEM) dependency_type = db_system target = trace_utils._get_target_for_db_dependency( target, db_system, attributes, ) - if SpanAttributes.DB_STATEMENT in attributes: + if DB_QUERY_TEXT in attributes: + data = attributes[DB_QUERY_TEXT] + elif SpanAttributes.DB_STATEMENT in attributes: data = attributes[SpanAttributes.DB_STATEMENT] + elif DB_OPERATION_NAME in attributes: + data = attributes[DB_OPERATION_NAME] elif SpanAttributes.DB_OPERATION in attributes: data = attributes[SpanAttributes.DB_OPERATION] elif SpanAttributes.MESSAGING_SYSTEM in attributes: diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py index 7b94a2fc3a3e..53744df7eaee 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py @@ -427,9 +427,7 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem: data.result_code = str(status_code) elif DB_SYSTEM_NAME in span.attributes or SpanAttributes.DB_SYSTEM in span.attributes: # Database # Prefer the new stable `db.system.name`, fall back to the deprecated `db.system`. - print("Span attributes", span.attributes) db_system = span.attributes.get(DB_SYSTEM_NAME) or span.attributes.get(SpanAttributes.DB_SYSTEM) - print(db_system) if db_system == DbSystemValues.MYSQL.value: data.type = "mysql" elif db_system == DbSystemValues.POSTGRESQL.value: diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py index de663c0ece26..56333350c38e 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py @@ -164,9 +164,7 @@ def _get_target_for_dependency_from_peer(attributes: Attributes) -> Optional[str db_system_for_port = attributes.get(db_attributes.DB_SYSTEM_NAME) or attributes.get( SpanAttributes.DB_SYSTEM ) - if port != _get_default_port_http(attributes) and port != _get_default_port_db( - str(db_system_for_port) - ): + if port != _get_default_port_http(attributes) and port != _get_default_port_db(str(db_system_for_port)): target = "{}:{}".format(target, port) return target diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/quickpulse/test_types.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/quickpulse/test_types.py index e63251d9dbfe..4be66c7d8a93 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/quickpulse/test_types.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/quickpulse/test_types.py @@ -9,6 +9,12 @@ from opentelemetry._logs import LogRecord from opentelemetry.sdk.trace import ReadableSpan from opentelemetry.semconv._incubating.attributes import gen_ai_attributes +from opentelemetry.semconv.attributes.db_attributes import ( + DB_NAMESPACE, + DB_OPERATION_NAME, + DB_QUERY_TEXT, + DB_SYSTEM_NAME, +) from opentelemetry.semconv.attributes.http_attributes import ( HTTP_REQUEST_METHOD, HTTP_RESPONSE_STATUS_CODE, @@ -184,6 +190,26 @@ def test_db_dependency(self): self.assertEqual(result.data, "SELECT * FROM table") self.assertEqual(result.target, "mysql") + def test_db_dependency_stable_semconv(self): + self.span.kind = SpanKind.CLIENT + self.span.attributes = { + DB_SYSTEM_NAME: "postgresql", + DB_QUERY_TEXT: "SELECT * FROM table", + DB_NAMESPACE: "database", + } + result = _DependencyData._from_span(self.span) + self.assertEqual(result.type, "postgresql") + self.assertEqual(result.data, "SELECT * FROM table") + self.assertEqual(result.target, "database") + + self.span.attributes = { + DB_SYSTEM_NAME: "postgresql", + DB_OPERATION_NAME: "SELECT", + } + result = _DependencyData._from_span(self.span) + self.assertEqual(result.data, "SELECT") + self.assertEqual(result.target, "postgresql") + def test_messaging_dependency(self): self.span.kind = SpanKind.CLIENT self.span.attributes = {SpanAttributes.MESSAGING_SYSTEM: "kafka"} diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py index 5f683cce320b..85c1a8991ee8 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py @@ -593,7 +593,7 @@ def test_span_to_envelope_client_db(self): start_time = 1575494316027613500 end_time = start_time + 1001000000 - # SpanKind.CLIENT Db + # SpanKind.CLIENT Db, deprecated semconv span = trace._Span( name="test", context=SpanContext( @@ -661,6 +661,24 @@ def test_span_to_envelope_client_db(self): envelope = exporter._span_to_envelope(span) self.assertEqual(envelope.data.base_data.target, "postgresql") + # Stable semconv + span._attributes = { + "db.system.name": "postgresql", + "db.query.text": "SELECT * from stable_test", + "db.namespace": "stableDb", + } + envelope = exporter._span_to_envelope(span) + self.assertEqual(envelope.data.base_data.type, "postgresql") + self.assertEqual(envelope.data.base_data.data, "SELECT * from stable_test") + self.assertEqual(envelope.data.base_data.target, "stableDb") + + span._attributes = { + "db.system.name": "postgresql", + "db.operation.name": "SELECT", + } + envelope = exporter._span_to_envelope(span) + self.assertEqual(envelope.data.base_data.data, "SELECT") + # Type span._attributes = { "db.system": "mssql", From 9b34f3211b25580977632548dc0506a7a91f4008 Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Fri, 11 Sep 2026 09:08:05 -0700 Subject: [PATCH 03/11] Update CHANGELOG --- .../azure-monitor-opentelemetry-exporter/CHANGELOG.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md index 91cd671e79bc..08d8799b86e0 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md @@ -7,12 +7,9 @@ ### Breaking Changes ### Bugs Fixed -- Recognize the new stable OpenTelemetry database semantic conventions +- Update to the new stable OpenTelemetry database semantic conventions (`db.system.name`, `db.query.text`, `db.operation.name`, `db.namespace`) when - mapping `CLIENT` spans to `RemoteDependencyData`. Previously only the - deprecated attributes (`db.system`, `db.statement`, `db.operation`, `db.name`) - were recognized, causing dependency `Type` to be reported as `N/A` for spans - emitted with the newer conventions. + mapping `CLIENT` spans to `RemoteDependencyData`. ### Other Changes From 3b021ef828548ace21bf6f4a7edb2df18fbe6fe6 Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Fri, 11 Sep 2026 09:10:48 -0700 Subject: [PATCH 04/11] Update CHANGELOG --- sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md index 08d8799b86e0..a0e7f0db5e3c 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/CHANGELOG.md @@ -9,7 +9,8 @@ ### Bugs Fixed - Update to the new stable OpenTelemetry database semantic conventions (`db.system.name`, `db.query.text`, `db.operation.name`, `db.namespace`) when - mapping `CLIENT` spans to `RemoteDependencyData`. + mapping `CLIENT` spans to `RemoteDependencyData` + ([#48979](https://github.com/Azure/azure-sdk-for-python/pull/48979)) ### Other Changes From 9e25d2d0dc1b48bb79c5b462deb7d49c44a891e3 Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Fri, 11 Sep 2026 10:28:54 -0700 Subject: [PATCH 05/11] Fix lint --- .../monitor/opentelemetry/exporter/export/trace/_exporter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py index 53744df7eaee..2f6256d87610 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py @@ -441,7 +441,8 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem: else: data.type = db_system # data is the full statement or operation - # Prefer new `db.query.text` / `db.operation.name`, fall back to deprecated `db.statement` / `db.operation`. + # Prefer new `db.query.text` / `db.operation.name`, + # fall back to deprecated `db.statement` / `db.operation`. if DB_QUERY_TEXT in span.attributes: data.data = span.attributes[DB_QUERY_TEXT] elif SpanAttributes.DB_STATEMENT in span.attributes: From 4cfbde592887206d3140ba2305334dce821788ff Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Fri, 11 Sep 2026 12:23:17 -0700 Subject: [PATCH 06/11] Fix lint --- .../monitor/opentelemetry/exporter/export/trace/_exporter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py index 2f6256d87610..3e039d315721 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py @@ -441,7 +441,7 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem: else: data.type = db_system # data is the full statement or operation - # Prefer new `db.query.text` / `db.operation.name`, + # Prefer new `db.query.text` / `db.operation.name`, # fall back to deprecated `db.statement` / `db.operation`. if DB_QUERY_TEXT in span.attributes: data.data = span.attributes[DB_QUERY_TEXT] From d95672fa55f00a67a902e137ac325268120ffcfc Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Fri, 11 Sep 2026 16:42:04 -0700 Subject: [PATCH 07/11] Use stable server.address and server.port --- .../monitor/opentelemetry/exporter/export/trace/_utils.py | 7 +++++++ .../tests/quickpulse/test_types.py | 3 ++- .../tests/trace/test_trace.py | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py index 56333350c38e..268b9760c6e7 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py @@ -234,6 +234,13 @@ def _get_target_for_db_dependency( attributes: Attributes, ) -> Optional[str]: if attributes: + if not target: + server_address = attributes.get(server_attributes.SERVER_ADDRESS) + if server_address: + target = str(server_address) + server_port = attributes.get(server_attributes.SERVER_PORT) + if server_port and server_port != _get_default_port_db(str(db_system)): + target = "{}:{}".format(target, server_port) # Prefer new stable `db.namespace`, fall back to deprecated `db.name`. db_name = attributes.get(db_attributes.DB_NAMESPACE) or attributes.get(SpanAttributes.DB_NAME) if db_name: diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/quickpulse/test_types.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/quickpulse/test_types.py index 4be66c7d8a93..b4465dca1f19 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/quickpulse/test_types.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/quickpulse/test_types.py @@ -196,11 +196,12 @@ def test_db_dependency_stable_semconv(self): DB_SYSTEM_NAME: "postgresql", DB_QUERY_TEXT: "SELECT * FROM table", DB_NAMESPACE: "database", + "server.address": "stable-server", } result = _DependencyData._from_span(self.span) self.assertEqual(result.type, "postgresql") self.assertEqual(result.data, "SELECT * FROM table") - self.assertEqual(result.target, "database") + self.assertEqual(result.target, "stable-server|database") self.span.attributes = { DB_SYSTEM_NAME: "postgresql", diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py index 85c1a8991ee8..221003eacd61 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace.py @@ -666,11 +666,13 @@ def test_span_to_envelope_client_db(self): "db.system.name": "postgresql", "db.query.text": "SELECT * from stable_test", "db.namespace": "stableDb", + "server.address": "stable-server", + "server.port": 15432, } envelope = exporter._span_to_envelope(span) self.assertEqual(envelope.data.base_data.type, "postgresql") self.assertEqual(envelope.data.base_data.data, "SELECT * from stable_test") - self.assertEqual(envelope.data.base_data.target, "stableDb") + self.assertEqual(envelope.data.base_data.target, "stable-server:15432|stableDb") span._attributes = { "db.system.name": "postgresql", From 80cbdb1d0630769ddb808ecf6c6cef7d374f6e2a Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Mon, 14 Sep 2026 09:10:23 -0700 Subject: [PATCH 08/11] Retrigger CI/CD pipeline From 7a3e8befadbe75b1e4178ee728187b4b4460942d Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Mon, 14 Sep 2026 12:19:57 -0700 Subject: [PATCH 09/11] Fix comments --- .../monitor/opentelemetry/exporter/_quickpulse/_types.py | 2 ++ .../monitor/opentelemetry/exporter/export/trace/_exporter.py | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_quickpulse/_types.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_quickpulse/_types.py index 2f95780b0354..a053fa84faa2 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_quickpulse/_types.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/_quickpulse/_types.py @@ -127,6 +127,8 @@ def _from_span(span: ReadableSpan): db_system, attributes, ) + # Use query text when available, otherwise fall back to the operation name. + # Support both stable and deprecated semantic conventions. if DB_QUERY_TEXT in attributes: data = attributes[DB_QUERY_TEXT] elif SpanAttributes.DB_STATEMENT in attributes: diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py index 3e039d315721..536a20015efe 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_exporter.py @@ -440,9 +440,8 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem: data.type = "SQL" else: data.type = db_system - # data is the full statement or operation - # Prefer new `db.query.text` / `db.operation.name`, - # fall back to deprecated `db.statement` / `db.operation`. + # Use query text when available, otherwise fall back to the operation name. + # Support both stable and deprecated semantic conventions. if DB_QUERY_TEXT in span.attributes: data.data = span.attributes[DB_QUERY_TEXT] elif SpanAttributes.DB_STATEMENT in span.attributes: From cb04c41668e5d0e15f8058ad991b9c4cdbfcbc89 Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Mon, 14 Sep 2026 15:18:46 -0700 Subject: [PATCH 10/11] Address feedback --- .../exporter/export/trace/_utils.py | 14 ++++++++++---- .../tests/trace/test_trace_utils.py | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py index 268b9760c6e7..c47bab8f6790 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py @@ -12,6 +12,8 @@ url_attributes, user_agent_attributes, ) + +from opentelemetry.semconv._incubating.attributes import db_attributes as db_attributes_incubating from opentelemetry.context import Context from opentelemetry.trace import get_current_span from opentelemetry.sdk.trace.sampling import ( @@ -39,16 +41,16 @@ def _get_default_port_db(db_system: str) -> int: return 9042 if db_system in (DbSystemValues.MARIADB.value, DbSystemValues.MYSQL.value): return 3306 - if db_system == DbSystemValues.MSSQL.value: + if db_system == DbSystemValues.MSSQL.value or db_system == db_attributes.DbSystemNameValues.MICROSOFT_SQL_SERVER.value: return 1433 # TODO: Add in memcached if db_system == "memcached": return 11211 - if db_system == DbSystemValues.DB2.value: + if db_system == DbSystemValues.DB2.value or db_system == db_attributes_incubating.DbSystemNameValues.IBM_DB2.value: return 50000 - if db_system == DbSystemValues.ORACLE.value: + if db_system == DbSystemValues.ORACLE.value or db_system == db_attributes_incubating.DbSystemNameValues.ORACLE_DB.value: return 1521 - if db_system == DbSystemValues.H2.value: + if db_system == DbSystemValues.H2.value or db_system == db_attributes_incubating.DbSystemNameValues.H2DATABASE.value: return 8082 if db_system == DbSystemValues.DERBY.value: return 1527 @@ -69,15 +71,19 @@ def _get_default_port_http(attributes: Attributes) -> int: def _is_sql_db(db_system: str) -> bool: return db_system in ( DbSystemValues.DB2.value, + db_attributes_incubating.DbSystemNameValues.IBM_DB2.value, DbSystemValues.DERBY.value, DbSystemValues.MARIADB.value, DbSystemValues.MSSQL.value, + db_attributes.DbSystemNameValues.MICROSOFT_SQL_SERVER.value, DbSystemValues.ORACLE.value, + db_attributes_incubating.DbSystemNameValues.ORACLE_DB.value, DbSystemValues.SQLITE.value, DbSystemValues.OTHER_SQL.value, # spell-checker:ignore HSQLDB DbSystemValues.HSQLDB.value, DbSystemValues.H2.value, + db_attributes_incubating.DbSystemNameValues.H2DATABASE.value, ) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace_utils.py index ae4ddbef6d01..e12710ef5cf9 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/tests/trace/test_trace_utils.py @@ -8,6 +8,8 @@ from azure.monitor.opentelemetry.exporter.export.trace._utils import ( _get_DJB2_sample_score, + _get_default_port_db, + _is_sql_db, ) from azure.monitor.opentelemetry.exporter._constants import ( @@ -17,6 +19,22 @@ ) +class TestDatabaseSystemNames(unittest.TestCase): + def test_legacy_and_stable_names(self): + test_cases = ( + ("h2", "h2database", 8082), + ("db2", "ibm.db2", 50000), + ("mssql", "microsoft.sql_server", 1433), + ("oracle", "oracle.db", 1521), + ) + + for legacy_name, stable_name, default_port in test_cases: + for db_system in (legacy_name, stable_name): + with self.subTest(db_system=db_system): + self.assertTrue(_is_sql_db(db_system)) + self.assertEqual(_get_default_port_db(db_system), default_port) + + class TestGetDJB2SampleScore(unittest.TestCase): """Test cases for _get_DJB2_sample_score function.""" From b74173ca9c223df6fae89e27d44470a31816d6e7 Mon Sep 17 00:00:00 2001 From: Radhika Gupta Date: Tue, 15 Sep 2026 08:39:53 -0700 Subject: [PATCH 11/11] Fix lint --- .../monitor/opentelemetry/exporter/export/trace/_utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py index c47bab8f6790..82fcbef8a240 100644 --- a/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py +++ b/sdk/monitor/azure-monitor-opentelemetry-exporter/azure/monitor/opentelemetry/exporter/export/trace/_utils.py @@ -41,16 +41,16 @@ def _get_default_port_db(db_system: str) -> int: return 9042 if db_system in (DbSystemValues.MARIADB.value, DbSystemValues.MYSQL.value): return 3306 - if db_system == DbSystemValues.MSSQL.value or db_system == db_attributes.DbSystemNameValues.MICROSOFT_SQL_SERVER.value: + if db_system in (DbSystemValues.MSSQL.value, db_attributes.DbSystemNameValues.MICROSOFT_SQL_SERVER.value): return 1433 # TODO: Add in memcached if db_system == "memcached": return 11211 - if db_system == DbSystemValues.DB2.value or db_system == db_attributes_incubating.DbSystemNameValues.IBM_DB2.value: + if db_system in (DbSystemValues.DB2.value, db_attributes_incubating.DbSystemNameValues.IBM_DB2.value): return 50000 - if db_system == DbSystemValues.ORACLE.value or db_system == db_attributes_incubating.DbSystemNameValues.ORACLE_DB.value: + if db_system in (DbSystemValues.ORACLE.value, db_attributes_incubating.DbSystemNameValues.ORACLE_DB.value): return 1521 - if db_system == DbSystemValues.H2.value or db_system == db_attributes_incubating.DbSystemNameValues.H2DATABASE.value: + if db_system in (DbSystemValues.H2.value, db_attributes_incubating.DbSystemNameValues.H2DATABASE.value): return 8082 if db_system == DbSystemValues.DERBY.value: return 1527