Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
29edd6a
PYTHON-5947 Ignore .worktrees/ for local worktree isolation
blink1073 Jul 27, 2026
85b5635
PYTHON-5947 Add implementation plan for operation/transaction spans
blink1073 Jul 28, 2026
62a3746
PYTHON-5947 Add operation-span primitives to pymongo._otel
blink1073 Jul 28, 2026
70f2e80
PYTHON-5947 Revert accidental opentelemetry-sdk requirement addition
blink1073 Jul 28, 2026
404fa4d
PYTHON-5947 Add transaction pseudo-span primitives to pymongo._otel
blink1073 Jul 28, 2026
6ecf29c
PYTHON-5947 Add _OperationTelemetry class
blink1073 Jul 28, 2026
b67f77d
PYTHON-5947 Wire operation spans into the retryable read/write loop
blink1073 Jul 28, 2026
df42a32
PYTHON-5947 Pin sensitive-command operation-span gap in otel test
blink1073 Jul 28, 2026
815cb60
PYTHON-5947 Add transaction pseudo-spans
blink1073 Jul 28, 2026
51463ea
PYTHON-5947 Cover transaction early-return and retried-commit span paths
blink1073 Jul 28, 2026
165ea43
PYTHON-5947 Add operation span for unacknowledged client bulk writes
blink1073 Jul 28, 2026
3f0e7ca
PYTHON-5947 Update tracing docs for operation/transaction spans
blink1073 Jul 28, 2026
cbdc779
PYTHON-5947 Wire observeTracingMessages/expectTracingMessages into th…
blink1073 Jul 28, 2026
c8ae168
PYTHON-5947 Vendor OpenTelemetry unified spec tests and drop redundan…
blink1073 Jul 28, 2026
df50944
PYTHON-5947 Add regression test for _truncate_documents falsy-value bug
blink1073 Jul 28, 2026
b9a97bb
PYTHON-5947 Fix OTel operation-span naming/exception-attribute bugs f…
blink1073 Jul 28, 2026
6e5d940
PYTHON-5947 Add regression tests and refresh stale comments for OTel …
blink1073 Jul 28, 2026
488edd0
PYTHON-5947 Add replica-set coverage to the OTel Evergreen variant
blink1073 Jul 28, 2026
0de5fb9
PYTHON-5947 Remove internal SDD planning doc from git tracking
blink1073 Jul 28, 2026
5cffd77
PYTHON-5947 Add design spec for remaining OTel span coverage gaps
blink1073 Jul 28, 2026
3b8bf01
PYTHON-5947 Add implementation plan for OTel span coverage gaps
blink1073 Jul 28, 2026
a297446
PYTHON-5947 Add eager attributes and detached mode to operation spans
blink1073 Jul 28, 2026
04597f0
PYTHON-5947 Fix duplicate exception recording in use_operation_span
blink1073 Jul 28, 2026
f95d082
PYTHON-5947 Plumb dbname/collection and caller-owned spans through th…
blink1073 Jul 28, 2026
14b4e4c
PYTHON-5947 Thread dbname/collection to operation spans from all call…
blink1073 Jul 28, 2026
e28216e
PYTHON-5947 Fix change-stream namespace misclassification in _target_…
blink1073 Jul 28, 2026
7cbb6c6
PYTHON-5947 Nest find cursor getMores under one operation span
blink1073 Jul 28, 2026
bb2e8cf
PYTHON-5947 Nest command cursor getMores under their operation span
blink1073 Jul 28, 2026
bc09330
PYTHON-5947 Nest client bulk-write results cursor getMores under bulk…
blink1073 Jul 28, 2026
e8c1e2e
PYTHON-5947 Add operation spans for killCursors and endSessions
blink1073 Jul 28, 2026
610cc7e
PYTHON-5947 Reset OpenTelemetry context in the async periodic executor
blink1073 Jul 28, 2026
02340a4
PYTHON-5947 Add withTransaction span and fix retried-commit transacti…
blink1073 Jul 28, 2026
d321301
PYTHON-5947 Reuse one transaction span across with_transaction retries
blink1073 Jul 28, 2026
d91035d
PYTHON-5947 Guard against reentrant with_transaction span leak
blink1073 Jul 28, 2026
0b9f50c
PYTHON-5947 Document expanded OTel span coverage
blink1073 Jul 28, 2026
4350a1b
PYTHON-5947 Mention background-monitor span fix, polish changelog bullet
blink1073 Jul 28, 2026
a80e2a4
PYTHON-5947 Fix flaky otel span-capture cross-talk from stale monitors
blink1073 Jul 28, 2026
fa8ee79
PYTHON-5947 Route every managed test client through the monitor join
blink1073 Jul 28, 2026
2acf149
PYTHON-5947 Gate the monitor-join cleanup on tracing being enabled
blink1073 Jul 28, 2026
a0af1c2
PYTHON-5947 Fix with_transaction() clobbering a concurrent direct-API…
blink1073 Jul 28, 2026
6218352
PYTHON-5947 End single-batch command cursors' operation spans at cons…
blink1073 Jul 28, 2026
d4c973d
PYTHON-5947 Address final-review minor findings (assert, comment, cle…
blink1073 Jul 28, 2026
f40a62d
PYTHON-5947 Remove internal SDD planning docs from git tracking
blink1073 Jul 29, 2026
78723c5
PYTHON-5947 Tighten the OpenTelemetry changelog and docstring entries
blink1073 Jul 29, 2026
0e6aea2
PYTHON-5947 Clarify the OpenTelemetry span-nesting wording
blink1073 Jul 29, 2026
71e7f96
PYTHON-5947 Let test_operation_id_retry tolerate added _CommandTeleme…
blink1073 Jul 29, 2026
a4963f2
PYTHON-5947 Drop eager dbname/collection threading from the retry layer
blink1073 Jul 29, 2026
ca797ae
PYTHON-5947 Centralize namespace-parsing logic
blink1073 Jul 29, 2026
a7ec812
PYTHON-5947 Refresh a change-stream test comment after _target_namesp…
blink1073 Jul 29, 2026
6d3a17c
PYTHON-5947 Describe current behavior in the client bulk write span c…
blink1073 Jul 29, 2026
84679d3
PYTHON-5947 Extract with_transaction's retry loop and trim span comments
blink1073 Jul 29, 2026
1238aa4
PYTHON-5947 Restore original formatting at untouched retryable call s…
blink1073 Jul 29, 2026
6529f69
PYTHON-5947 Restore base formatting at three more untouched call sites
blink1073 Jul 29, 2026
b516237
PYTHON-5947 Declare cursor type on its own line
blink1073 Jul 29, 2026
5a0de65
PYTHON-5947 Let _ClientConnectionRetryable own its operation span
blink1073 Jul 29, 2026
05f2708
PYTHON-5947 Extract _retryable_read_cursor to dedupe cursor telemetry…
blink1073 Jul 29, 2026
1933c9d
PYTHON-5947 Leave _list_databases and _retryable_read_command untouched
blink1073 Jul 29, 2026
0b1b1d0
PYTHON-5947 Mirror _retryable_read's signature in _retryable_read_cursor
blink1073 Jul 29, 2026
49588fd
PYTHON-5947 Drop a trailing comma that forced a call to reformat
blink1073 Jul 29, 2026
b1ba1b0
PYTHON-5947 Fix CI-only OpenTelemetry test failures on pre-4.4/8.2 se…
blink1073 Jul 29, 2026
92d85b3
PYTHON-5947 Avoid em-dashes and 'via' in new comments and docs
blink1073 Jul 30, 2026
3afc2b4
PYTHON-5947 Rewrite ASCII double-dash prose in OTel comments and docs…
blink1073 Jul 30, 2026
bc9e680
PYTHON-5947 Reword three comments left awkward by the dash removal
blink1073 Jul 30, 2026
28ff04e
PYTHON-5947 Move OTel naming policy out of _telemetry.py into _otel.py
blink1073 Jul 30, 2026
eda80f3
PYTHON-5947 Document the per-attempt command span invariant
blink1073 Jul 30, 2026
c3a2ac4
PYTHON-5947 Drop otel tests the vendored spec suite already covers
blink1073 Jul 30, 2026
fbede23
PYTHON-5947 Move span attribute normalization into MatchEvaluatorUtil
blink1073 Jul 30, 2026
55ccb0b
PYTHON-5947 Drop the monitor-join test cleanup, heartbeats emit no spans
blink1073 Jul 30, 2026
0529b08
PYTHON-5947 Carry the DRIVERS-3597 fixture fixes as a spec patch
blink1073 Jul 31, 2026
ef9dc97
PYTHON-5947 Reset contextvars in the sync periodic executor too
blink1073 Jul 31, 2026
97e8e80
Merge remote-tracking branch 'upstream/otel' into PYTHON-5947-otel-impl
blink1073 Aug 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .evergreen/generated_configs/variants.yml
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ buildvariants:
- name: otel-rhel8
tasks:
- name: .test-non-standard .standalone-noauth-nossl
- name: .test-non-standard .replica_set-noauth-ssl
display_name: OTel RHEL8
run_on:
- rhel87-small
Expand Down
3 changes: 3 additions & 0 deletions .evergreen/resync-specs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ do
cpjson command-logging-and-monitoring/tests/logging command_logging
cpjson command-logging-and-monitoring/tests/monitoring command_monitoring
;;
open-telemetry|otel|open_telemetry)
cpjson open-telemetry/tests open_telemetry
;;
crud|CRUD)
cpjson crud/tests/ crud
;;
Expand Down
11 changes: 10 additions & 1 deletion .evergreen/scripts/generate_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,16 @@ def create_otel_variants():
expansions = dict(TEST_NAME="otel", COVERAGE="1")
return [
create_variant(
[".test-non-standard .standalone-noauth-nossl"],
[
".test-non-standard .standalone-noauth-nossl",
# Transaction spans (test/open_telemetry/transaction/*.json,
# test_otel.py's @require_transactions tests) need a replica set
# (they're skipped entirely on a standalone topology), so also
# run against one, mirroring how other variants in this file
# (e.g. PyOpenSSL's ".replica_set-noauth-ssl") pair a
# standalone/standard selector with a replica-set one.
".test-non-standard .replica_set-noauth-ssl",
],
get_variant_name("OTel", host),
host=host,
tags=["pr"],
Expand Down
259 changes: 259 additions & 0 deletions .evergreen/spec-patch/PYTHON-5979.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
diff --git b/test/open_telemetry/operation/aggregate.json a/test/open_telemetry/operation/aggregate.json
index ad8e189b..07c30a67 100644
--- b/test/open_telemetry/operation/aggregate.json
+++ a/test/open_telemetry/operation/aggregate.json
@@ -26,13 +26,6 @@
}
}
],
- "initialData": [
- {
- "collectionName": "test",
- "databaseName": "operation-aggregate",
- "documents": []
- }
- ],
"tests": [
{
"description": "aggregation",
diff --git b/test/open_telemetry/operation/atlas_search.json a/test/open_telemetry/operation/atlas_search.json
index b787a730..e961e7a2 100644
--- b/test/open_telemetry/operation/atlas_search.json
+++ a/test/open_telemetry/operation/atlas_search.json
@@ -26,13 +26,6 @@
}
}
],
- "initialData": [
- {
- "collectionName": "test",
- "databaseName": "operation-atlas-search",
- "documents": []
- }
- ],
"runOnRequirements": [
{
"minServerVersion": "7.0.5",
diff --git b/test/open_telemetry/operation/create_collection.json a/test/open_telemetry/operation/create_collection.json
index 8522e198..2cbbe8c6 100644
--- b/test/open_telemetry/operation/create_collection.json
+++ a/test/open_telemetry/operation/create_collection.json
@@ -19,24 +19,10 @@
}
}
],
- "initialData": [
- {
- "collectionName": "newlyCreatedCollection",
- "databaseName": "operation-create-collection",
- "documents": []
- }
- ],
"tests": [
{
"description": "create collection",
"operations": [
- {
- "object": "database0",
- "name": "dropCollection",
- "arguments": {
- "collection": "newlyCreatedCollection"
- }
- },
{
"object": "database0",
"name": "createCollection",
@@ -50,72 +36,6 @@
"client": "client0",
"ignoreExtraSpans": false,
"spans": [
- {
- "name": "dropCollection operation-create-collection.newlyCreatedCollection",
- "attributes": {
- "db.system.name": "mongodb",
- "db.namespace": "operation-create-collection",
- "db.collection.name": "newlyCreatedCollection",
- "db.operation.name": "dropCollection",
- "db.operation.summary": "dropCollection operation-create-collection.newlyCreatedCollection"
- },
- "nested": [
- {
- "name": "drop",
- "attributes": {
- "db.system.name": "mongodb",
- "db.namespace": "operation-create-collection",
- "db.collection.name": "newlyCreatedCollection",
- "db.command.name": "drop",
- "network.transport": "tcp",
- "db.mongodb.cursor_id": {
- "$$exists": false
- },
- "db.response.status_code": {
- "$$exists": false
- },
- "exception.message": {
- "$$exists": false
- },
- "exception.type": {
- "$$exists": false
- },
- "exception.stacktrace": {
- "$$exists": false
- },
- "server.address": {
- "$$type": "string"
- },
- "server.port": {
- "$$type": [
- "int",
- "long"
- ]
- },
- "db.query.summary": "drop operation-create-collection.newlyCreatedCollection",
- "db.query.text": {
- "$$matchAsDocument": {
- "$$matchAsRoot": {
- "drop": "newlyCreatedCollection"
- }
- }
- },
- "db.mongodb.server_connection_id": {
- "$$type": [
- "int",
- "long"
- ]
- },
- "db.mongodb.driver_connection_id": {
- "$$type": [
- "int",
- "long"
- ]
- }
- }
- }
- ]
- },
{
"name": "createCollection operation-create-collection.newlyCreatedCollection",
"attributes": {
diff --git b/test/open_telemetry/operation/create_indexes.json a/test/open_telemetry/operation/create_indexes.json
index d62d47a9..ff1e86d0 100644
--- b/test/open_telemetry/operation/create_indexes.json
+++ a/test/open_telemetry/operation/create_indexes.json
@@ -26,13 +26,6 @@
}
}
],
- "initialData": [
- {
- "collectionName": "test",
- "databaseName": "operation-create-indexes",
- "documents": []
- }
- ],
"tests": [
{
"description": "create indexes",
diff --git b/test/open_telemetry/operation/delete.json a/test/open_telemetry/operation/delete.json
index 70d6babc..151c7abf 100644
--- b/test/open_telemetry/operation/delete.json
+++ a/test/open_telemetry/operation/delete.json
@@ -26,13 +26,6 @@
}
}
],
- "initialData": [
- {
- "collectionName": "test",
- "databaseName": "operation-delete",
- "documents": []
- }
- ],
"tests": [
{
"description": "delete elements",
diff --git b/test/open_telemetry/operation/drop_collection.json a/test/open_telemetry/operation/drop_collection.json
index 4dea1252..cc5358c1 100644
--- b/test/open_telemetry/operation/drop_collection.json
+++ a/test/open_telemetry/operation/drop_collection.json
@@ -31,13 +31,6 @@
}
}
],
- "initialData": [
- {
- "collectionName": "test",
- "databaseName": "operation-drop-collection",
- "documents": []
- }
- ],
"tests": [
{
"description": "drop collection",
diff --git b/test/open_telemetry/operation/drop_indexes.json a/test/open_telemetry/operation/drop_indexes.json
index e8f20fbb..91126c92 100644
--- b/test/open_telemetry/operation/drop_indexes.json
+++ a/test/open_telemetry/operation/drop_indexes.json
@@ -46,13 +46,6 @@
}
}
],
- "initialData": [
- {
- "collectionName": "test",
- "databaseName": "operation-drop-indexes",
- "documents": []
- }
- ],
"tests": [
{
"description": "drop indexes",
diff --git b/test/open_telemetry/operation/find_and_modify.json a/test/open_telemetry/operation/find_and_modify.json
index 291f1b61..7bacba57 100644
--- b/test/open_telemetry/operation/find_and_modify.json
+++ a/test/open_telemetry/operation/find_and_modify.json
@@ -26,13 +26,6 @@
}
}
],
- "initialData": [
- {
- "collectionName": "test",
- "databaseName": "operation-find-one-and-update",
- "documents": []
- }
- ],
"tests": [
{
"description": "findOneAndUpdate",
diff --git b/test/open_telemetry/operation/update.json a/test/open_telemetry/operation/update.json
index f31054dc..509c98be 100644
--- b/test/open_telemetry/operation/update.json
+++ a/test/open_telemetry/operation/update.json
@@ -26,13 +26,6 @@
}
}
],
- "initialData": [
- {
- "collectionName": "test",
- "databaseName": "operation-update",
- "documents": []
- }
- ],
"tests": [
{
"description": "update one element",
@@ -129,12 +122,6 @@
"$inc": {
"x": 1
}
- },
- "multi": {
- "$$unsetOrMatches": false
- },
- "upsert": {
- "$$unsetOrMatches": false
}
}
]
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,6 @@ server.log

# uv lockfiles
uv.lock

# Local git worktrees
.worktrees/
10 changes: 4 additions & 6 deletions bson/json_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -1115,20 +1115,18 @@ def _truncate_documents(obj: Any, max_length: int) -> tuple[Any, int]:
if hasattr(obj, "items"):
truncated: Any = {}
for k, v in obj.items():
truncated_v, remaining = _truncate_documents(v, remaining)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

These changes were needed for the new distinct.json, which has a falsey value for the field. These fields should not be dropped.

if truncated_v:
truncated[k] = truncated_v
if remaining <= 0:
break
truncated_v, remaining = _truncate_documents(v, remaining)
truncated[k] = truncated_v
return truncated, remaining
elif hasattr(obj, "__iter__") and not isinstance(obj, (str, bytes)):
truncated: Any = [] # type:ignore[no-redef]
for v in obj:
truncated_v, remaining = _truncate_documents(v, remaining)
if truncated_v:
truncated.append(truncated_v)
if remaining <= 0:
break
truncated_v, remaining = _truncate_documents(v, remaining)
truncated.append(truncated_v)
return truncated, remaining
else:
return _truncate(obj, remaining)
Expand Down
11 changes: 7 additions & 4 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ PyMongo 4.18 brings a number of changes including:
attempts, so consumers can correlate a retried operation's events. As a
result, ``operation_id`` is no longer equal to the per-attempt ``request_id``
for these operations.
- Added optional OpenTelemetry command-span support, conforming to the
- Added optional OpenTelemetry tracing support, conforming to the
`OpenTelemetry driver specification <https://github.com/mongodb/specifications/blob/master/source/open-telemetry/open-telemetry.md>`_.
Enable it with the ``tracing`` :class:`~pymongo.mongo_client.MongoClient`
option or the ``OTEL_PYTHON_INSTRUMENTATION_MONGODB_ENABLED`` environment
variable. Install the ``opentelemetry-api`` package, or use the
Every public API call produces an operation span, which contains one span
per command sent to the server. Inside a transaction, those operation spans
nest under a ``transaction`` span. Enable it with the
``tracing`` :class:`~pymongo.mongo_client.MongoClient` option or the
``OTEL_PYTHON_INSTRUMENTATION_MONGODB_ENABLED`` environment variable.
Install the ``opentelemetry-api`` package, or use the
``pymongo[opentelemetry]`` extra, to enable this feature.
- Fixed a potential out-of-bounds read in the C extension when decoding an
array of BSON documents. An embedded document whose declared length exceeds
Expand Down
Loading
Loading