Skip to content

opentelemetry-instrumentation-dbapi: implement proper handling of t-string queries#4697

Merged
xrmx merged 8 commits into
open-telemetry:mainfrom
herin049:fix/dbapi-t-strings
Jun 23, 2026
Merged

opentelemetry-instrumentation-dbapi: implement proper handling of t-string queries#4697
xrmx merged 8 commits into
open-telemetry:mainfrom
herin049:fix/dbapi-t-strings

Conversation

@herin049

Copy link
Copy Markdown
Contributor

Description

Implements proper handling of template string queries added in Python 3.14.

Fixes #4690

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

uv run tox -e py314-test-instrumentation-dbapi

Does This PR Require a Core Repo Change?

  • Yes. - Link to PR:
  • No.

Checklist:

See contributing.md for styleguide, changelog guidelines, and more.

  • Followed the style guidelines of this project
  • Changelogs have been updated
  • Unit tests have been added
  • Documentation has been updated

@herin049 herin049 requested a review from a team as a code owner June 13, 2026 20:37

@xrmx xrmx left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried writing a docker tests for this (need to merge main with test requirements updated):

diff --git a/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py b/tests/opentelemetry-docker-tests/tests/postgres/
test_psycopg_sqlcommenter.py
index cd7c8fcda..7b929fff8 100644
--- a/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py
+++ b/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py
@@ -1,6 +1,9 @@
 # Copyright The OpenTelemetry Authors
 # SPDX-License-Identifier: Apache-2.0
 
+import sys
+from unittest import skipIf
+
 import psycopg
 import psycopg2
 from test_psycopg_functional import (
@@ -89,3 +92,33 @@ class TestFunctionalPsycopg(TestBase):
 
         cursor.close()
         connection.close()
+
+    @skipIf(
+        sys.version_info < (3, 14),
+        reason="requires Python 3.14+ for t-strings",
+    )
+    def test_commenter_template_string(self):
+        connection = psycopg.connect(
+            dbname=POSTGRES_DB_NAME,
+            user=POSTGRES_USER,
+            password=POSTGRES_PASSWORD,
+            host=POSTGRES_HOST,
+            port=POSTGRES_PORT,
+        )
+        cursor = connection.cursor()
+        one = "1"
+        cursor.execute(t"SELECT {one};")
+        self.assertRegex(
+            cursor._query.query.decode("ascii"),
+            r"SELECT .1 /\*db_driver='psycopg(.*)',dbapi_level='\d.\d',dbapi_threadsafety=\d,driver_paramstyle=(.*),libpq_version=\d*,tracep
arent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;",
+        )
+
+        cursor.close()
+        connection.close()
diff --git a/tox.ini b/tox.ini
index f8315f465..f8800c9a0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1052,7 +1052,7 @@ commands =
   codespell
 
 [testenv:docker-tests]
-basepython: python3
+basepython: python3.14
 deps =
   {[testenv]test_deps}
   -r {toxinidir}/tests/opentelemetry-docker-tests/tests/test-requirements.txt

With tox -e docker-tests -- -k TestFunctionalPsycopg it pass but I see a:

WARNING  opentelemetry.attributes:__init__.py:125 Invalid type Template for attribute 'db.statement' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types

It's coming from this stacktrace:

  File "/home/rm/src/opentelemetry-python-contrib/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py", line 116, in test_commenter_template_string
    cursor.execute(query)
  File "/home/rm/src/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py", line 369, in execute
    return _cursor_tracer.traced_execution(
  File "/home/rm/src/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py", line 927, in traced_execution
    self._populate_span(span, cursor, *args)
  File "/home/rm/src/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py", line 808, in _populate_span
    _set_db_statement(span_attrs, statement, sem_conv_mode)

@xrmx xrmx moved this to Reviewed PRs that need fixes in Python PR digest Jun 18, 2026
@herin049

Copy link
Copy Markdown
Contributor Author

Tried writing a docker tests for this (need to merge main with test requirements updated):

diff --git a/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py b/tests/opentelemetry-docker-tests/tests/postgres/
test_psycopg_sqlcommenter.py
index cd7c8fcda..7b929fff8 100644
--- a/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py
+++ b/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py
@@ -1,6 +1,9 @@
 # Copyright The OpenTelemetry Authors
 # SPDX-License-Identifier: Apache-2.0
 
+import sys
+from unittest import skipIf
+
 import psycopg
 import psycopg2
 from test_psycopg_functional import (
@@ -89,3 +92,33 @@ class TestFunctionalPsycopg(TestBase):
 
         cursor.close()
         connection.close()
+
+    @skipIf(
+        sys.version_info < (3, 14),
+        reason="requires Python 3.14+ for t-strings",
+    )
+    def test_commenter_template_string(self):
+        connection = psycopg.connect(
+            dbname=POSTGRES_DB_NAME,
+            user=POSTGRES_USER,
+            password=POSTGRES_PASSWORD,
+            host=POSTGRES_HOST,
+            port=POSTGRES_PORT,
+        )
+        cursor = connection.cursor()
+        one = "1"
+        cursor.execute(t"SELECT {one};")
+        self.assertRegex(
+            cursor._query.query.decode("ascii"),
+            r"SELECT .1 /\*db_driver='psycopg(.*)',dbapi_level='\d.\d',dbapi_threadsafety=\d,driver_paramstyle=(.*),libpq_version=\d*,tracep
arent='\d{1,2}-[a-zA-Z0-9_]{32}-[a-zA-Z0-9_]{16}-\d{1,2}'\*/;",
+        )
+
+        cursor.close()
+        connection.close()
diff --git a/tox.ini b/tox.ini
index f8315f465..f8800c9a0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1052,7 +1052,7 @@ commands =
   codespell
 
 [testenv:docker-tests]
-basepython: python3
+basepython: python3.14
 deps =
   {[testenv]test_deps}
   -r {toxinidir}/tests/opentelemetry-docker-tests/tests/test-requirements.txt

With tox -e docker-tests -- -k TestFunctionalPsycopg it pass but I see a:

WARNING  opentelemetry.attributes:__init__.py:125 Invalid type Template for attribute 'db.statement' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types

It's coming from this stacktrace:

  File "/home/rm/src/opentelemetry-python-contrib/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_sqlcommenter.py", line 116, in test_commenter_template_string
    cursor.execute(query)
  File "/home/rm/src/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py", line 369, in execute
    return _cursor_tracer.traced_execution(
  File "/home/rm/src/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py", line 927, in traced_execution
    self._populate_span(span, cursor, *args)
  File "/home/rm/src/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py", line 808, in _populate_span
    _set_db_statement(span_attrs, statement, sem_conv_mode)

Let me take a look, my guess is that somehow the isinstance(obj, _Template) check is failing, producing the error you see.

@xrmx

xrmx commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

It looks like the get_statement called by psycopg is not the generic one :)

This removes the warning but I have no idea of any other effect:

diff --git a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py
index 5617335f7..43fedf992 100644
--- a/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py
+++ b/instrumentation/opentelemetry-instrumentation-psycopg/src/opentelemetry/instrumentation/psycopg/__init__.py
@@ -343,8 +343,8 @@ class CursorTracer(dbapi.CursorTracer):
 
         statement = args[0]
         if isinstance(statement, Composable):
-            statement = statement.as_string(cursor)
-        return statement
+            return statement.as_string(cursor)
+        return super().get_statement(cursor, args)
 
 
 def _new_cursor_factory(

So I think we should add a new unit test in psycopg as well.

Comment thread opentelemetry-instrumentation/tests/test_utils.py
@herin049 herin049 requested a review from xrmx June 23, 2026 04:01
@github-project-automation github-project-automation Bot moved this from Reviewed PRs that need fixes to Approved PRs in Python PR digest Jun 23, 2026
@xrmx xrmx added this pull request to the merge queue Jun 23, 2026
Merged via the queue into open-telemetry:main with commit 1ac85b1 Jun 23, 2026
766 checks passed
@github-project-automation github-project-automation Bot moved this from Approved PRs to Done in Python PR digest Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

dbapi / PsycopgInstrumentor does not handle PEP 750 t-string queries

3 participants