Skip to content

Commit 98d0a4a

Browse files
committed
feat(pymongo): introduce db.operation, refactor db.statement
This change updates the opentelemetry-instrumentation-pymongo to better align with OpenTelemetry semantic conventions and the behavior of other language instrumentations (e.g. NodeJS, Ruby, etc.). see https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/plugins/node/opentelemetry-instrumentation-mongodb/src/instrumentation.ts The key changes are: - The `db.operation` attribute is now used to record the MongoDB command name (e.g., find, insert). - The `db.statement` attribute is no longer populated by default. It is only recorded if the `capture_statement = True` option is passed to the instrumentor. - The span name has been made more specific, changing from `{db_name}.{command}` to `{db_name}.{collection}.{command}` when a collection is present. This provides more consistent and conventional telemetry data for MongoDB operations.
1 parent b74633a commit 98d0a4a

File tree

2 files changed

+37
-17
lines changed

2 files changed

+37
-17
lines changed

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

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ def started(self, event: monitoring.CommandStartedEvent):
136136
if not self.is_enabled or not is_instrumentation_enabled():
137137
return
138138
command_name = event.command_name
139-
span_name = f"{event.database_name}.{command_name}"
140-
statement = self._get_statement_by_command_name(command_name, event)
139+
span_name = _get_span_name(event)
141140
collection = event.command.get(event.command_name)
142141

143142
try:
@@ -147,7 +146,12 @@ def started(self, event: monitoring.CommandStartedEvent):
147146
SpanAttributes.DB_SYSTEM, DbSystemValues.MONGODB.value
148147
)
149148
span.set_attribute(SpanAttributes.DB_NAME, event.database_name)
150-
span.set_attribute(SpanAttributes.DB_STATEMENT, statement)
149+
span.set_attribute(SpanAttributes.DB_OPERATION, command_name)
150+
if self.capture_statement:
151+
span.set_attribute(
152+
SpanAttributes.DB_STATEMENT,
153+
_get_statement(event),
154+
)
151155
if collection:
152156
span.set_attribute(
153157
SpanAttributes.DB_MONGODB_COLLECTION, collection
@@ -210,16 +214,21 @@ def failed(self, event: monitoring.CommandFailedEvent):
210214
def _pop_span(self, event: CommandEvent) -> Span | None:
211215
return self._span_dict.pop(_get_span_dict_key(event), None)
212216

213-
def _get_statement_by_command_name(
214-
self, command_name: str, event: CommandEvent
215-
) -> str:
216-
statement = command_name
217-
command_attribute = COMMAND_TO_ATTRIBUTE_MAPPING.get(command_name)
218-
command = event.command.get(command_attribute)
219-
if command and self.capture_statement:
220-
statement += " " + str(command)
221-
return statement
222217

218+
def _get_span_name(event: CommandEvent) -> str:
219+
"""Get the span name for a given pymongo event."""
220+
command_name = event.command_name
221+
collection = event.command.get(command_name)
222+
if collection:
223+
return f"{event.database_name}.{collection}.{command_name}"
224+
return f"{event.database_name}.{command_name}"
225+
226+
def _get_statement(event: CommandEvent) -> str:
227+
"""Get the statement for a given pymongo event."""
228+
command_name = event.command_name
229+
command_attribute = COMMAND_TO_ATTRIBUTE_MAPPING.get(command_name)
230+
command = event.command.get(command_attribute)
231+
return f"{command}"
223232

224233
def _get_span_dict_key(
225234
event: CommandEvent,

instrumentation/opentelemetry-instrumentation-pymongo/tests/test_pymongo.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ def test_started(self):
6262
self.assertEqual(
6363
span.attributes[SpanAttributes.DB_NAME], "database_name"
6464
)
65-
self.assertEqual(span.attributes[SpanAttributes.DB_STATEMENT], "find")
65+
self.assertEqual(span.attributes[SpanAttributes.DB_OPERATION], "find")
66+
self.assertNotIn(SpanAttributes.DB_STATEMENT, span.attributes)
6667
self.assertEqual(
6768
span.attributes[SpanAttributes.NET_PEER_NAME], "test.com"
6869
)
@@ -210,7 +211,10 @@ def test_capture_statement_getmore(self):
210211

211212
self.assertEqual(
212213
span.attributes[SpanAttributes.DB_STATEMENT],
213-
"getMore test_collection",
214+
"test_collection",
215+
)
216+
self.assertEqual(
217+
span.attributes[SpanAttributes.DB_OPERATION], "getMore"
214218
)
215219

216220
def test_capture_statement_aggregate(self):
@@ -232,10 +236,13 @@ def test_capture_statement_aggregate(self):
232236
self.assertEqual(len(spans_list), 1)
233237
span = spans_list[0]
234238

235-
expected_statement = f"aggregate {pipeline}"
239+
expected_statement = f"{pipeline}"
236240
self.assertEqual(
237241
span.attributes[SpanAttributes.DB_STATEMENT], expected_statement
238242
)
243+
self.assertEqual(
244+
span.attributes[SpanAttributes.DB_OPERATION], "aggregate"
245+
)
239246

240247
def test_capture_statement_disabled_getmore(self):
241248
command_attrs = {
@@ -253,9 +260,11 @@ def test_capture_statement_disabled_getmore(self):
253260
span = spans_list[0]
254261

255262
self.assertEqual(
256-
span.attributes[SpanAttributes.DB_STATEMENT], "getMore"
263+
span.attributes[SpanAttributes.DB_OPERATION], "getMore"
257264
)
258265

266+
self.assertNotIn(SpanAttributes.DB_STATEMENT, span.attributes)
267+
259268
def test_capture_statement_disabled_aggregate(self):
260269
pipeline = [{"$match": {"status": "active"}}]
261270
command_attrs = {
@@ -273,9 +282,11 @@ def test_capture_statement_disabled_aggregate(self):
273282
span = spans_list[0]
274283

275284
self.assertEqual(
276-
span.attributes[SpanAttributes.DB_STATEMENT], "aggregate"
285+
span.attributes[SpanAttributes.DB_OPERATION], "aggregate"
277286
)
278287

288+
self.assertNotIn(SpanAttributes.DB_STATEMENT, span.attributes)
289+
279290

280291
class MockCommand:
281292
def __init__(self, command_attrs):

0 commit comments

Comments
 (0)