Skip to content

Commit 925570a

Browse files
committed
feat(tortoiseorm): replace db.statement.parameters with db.query.parameter.<key>
Replace db.statement.parameters with individual db.query.parameter.<key> attributes. Tortoise parameters are always positional (tuple from args[1:]), so a simple indexed loop is used.
1 parent 3a05186 commit 925570a

2 files changed

Lines changed: 31 additions & 7 deletions

File tree

instrumentation/opentelemetry-instrumentation-tortoiseorm/src/opentelemetry/instrumentation/tortoiseorm/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
)
5555
from opentelemetry.semconv._incubating.attributes.db_attributes import (
5656
DB_NAME,
57+
DB_QUERY_PARAMETER_TEMPLATE,
5758
DB_STATEMENT,
5859
DB_SYSTEM,
5960
DB_USER,
@@ -237,7 +238,9 @@ def _uninstrument(self, **kwargs):
237238
tortoise.contrib.pydantic.base.PydanticListModel, "from_queryset"
238239
)
239240

240-
def _hydrate_span_from_args(self, connection, query, parameters) -> dict:
241+
def _hydrate_span_from_args( # pylint: disable=too-many-branches
242+
self, connection, query, parameters
243+
) -> dict:
241244
"""Get network and database attributes from connection."""
242245
span_attributes = {}
243246
capabilities = getattr(connection, "capabilities", None)
@@ -268,7 +271,10 @@ def _hydrate_span_from_args(self, connection, query, parameters) -> dict:
268271

269272
if self.capture_parameters:
270273
if parameters is not None and len(parameters) > 0:
271-
span_attributes["db.statement.parameters"] = str(parameters)
274+
for idx, value in enumerate(parameters):
275+
span_attributes[f"{DB_QUERY_PARAMETER_TEMPLATE}.{idx}"] = (
276+
repr(value)
277+
)
272278

273279
return span_attributes
274280

instrumentation/opentelemetry-instrumentation-tortoiseorm/tests/test_tortoiseorm_instrumentation.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from opentelemetry.instrumentation.utils import suppress_instrumentation
2222
from opentelemetry.semconv._incubating.attributes.db_attributes import (
2323
DB_NAME,
24+
DB_QUERY_PARAMETER_TEMPLATE,
2425
DB_STATEMENT,
2526
DB_SYSTEM,
2627
)
@@ -30,6 +31,7 @@
3031
class MockModel(models.Model):
3132
id = fields.IntField(pk=True)
3233
name = fields.TextField()
34+
description = fields.TextField(default="")
3335

3436
def __str__(self):
3537
return self.name
@@ -87,15 +89,31 @@ def test_capture_parameters(self):
8789

8890
async def run():
8991
await self._init_tortoise()
90-
await MockModel.create(name="Test Parameterized")
92+
await MockModel.create(
93+
name="Test Capture Params", description="Multiple Params"
94+
)
9195

9296
self._async_call(run())
9397
spans = self.memory_exporter.get_finished_spans()
9498
insert_span = next(s for s in spans if s.name == "INSERT")
95-
self.assertIn("db.statement.parameters", insert_span.attributes)
96-
self.assertIn(
97-
"Test Parameterized",
98-
insert_span.attributes["db.statement.parameters"],
99+
self.assertEqual(
100+
insert_span.attributes[f"{DB_QUERY_PARAMETER_TEMPLATE}.0"],
101+
"['Test Capture Params', 'Multiple Params']",
102+
)
103+
104+
def test_capture_no_parameters(self):
105+
TortoiseORMInstrumentor().uninstrument()
106+
TortoiseORMInstrumentor().instrument(capture_parameters=True)
107+
108+
async def run():
109+
await self._init_tortoise()
110+
await MockModel.all()
111+
112+
self._async_call(run())
113+
spans = self.memory_exporter.get_finished_spans()
114+
select_span = next(s for s in spans if s.name == "SELECT")
115+
self.assertNotIn(
116+
f"{DB_QUERY_PARAMETER_TEMPLATE}.0", select_span.attributes
99117
)
100118

101119
def test_uninstrument(self):

0 commit comments

Comments
 (0)