Skip to content

PYTHON-5993 Add OpenTelemetry operation spans for cursor getMores - #2994

Draft
blink1073 wants to merge 8 commits into
PYTHON-5947-otel-3-unifiedfrom
PYTHON-5947-otel-4-getmore
Draft

PYTHON-5993 Add OpenTelemetry operation spans for cursor getMores#2994
blink1073 wants to merge 8 commits into
PYTHON-5947-otel-3-unifiedfrom
PYTHON-5947-otel-4-getmore

Conversation

@blink1073

@blink1073 blink1073 commented Aug 17, 2026

Copy link
Copy Markdown
Member

PYTHON-5993

Last of four PRs splitting #2964. Base is PYTHON-5947-otel-3-unified.

Branch Contents
1 PYTHON-5947-otel-1-operations operation spans
2 PYTHON-5947-otel-2-transactions transaction spans
3 PYTHON-5947-otel-3-unified unified runner and vendored fixtures
4 PYTHON-5947-otel-4-getmore getMore spans (this PR)
5 PYTHON-5947-otel-5-error-type error.type command span attribute

Changes in this PR

Gives each caller-driven getMore an operation span of its own, which the specification requires: an application may do unrelated work between batches, so nesting every getMore under the call that created the cursor would misrepresent the timing.

Implements DRIVERS-3598 (specifications#1973), which settles this: the spec previously said only that a command span nests under "the corresponding driver operation span", which is unambiguous only while an operation sends one command. Both readings passed the suite because no fixture exercised getMore.

  • One operation span per caller-driven batch, sibling to the cursor-creating call's span rather than nested under it.
  • A call that creates a cursor and drains it itself, such as list_collection_names or index_information, keeps a single span covering every getMore it sends.
  • db.mongodb.cursor_id holds the id the driver sent, even when the reply returns 0, and is omitted rather than reported as 0 for a cursor-creating command that leaves no cursor open.
  • No span is scoped to a cursor's lifetime, so a cursor that is never exhausted leaves nothing unfinished.
  • The client bulk-write results cursor reuses the enclosing bulkWrite span instead of adding spurious siblings.
  • A command cursor exhausted by its first batch closes its span promptly rather than at garbage collection.
  • Vendored the spec's getMore fixture, held back from PR 3, plus its prose tests 3 and 4 for what the unified format cannot express.

Change streams deliberately get neither treatment. A change stream can tail indefinitely, so a span covering its lifetime would never end or be exported; each getMore gets a short-lived sibling span instead. There is a comment on the code saying so.

The fixture is a local deviation until specifications#1973 merges. get_more.json is not on mongodb/specifications master yet, so running resync-specs.sh before that lands will delete it. The file here is byte-identical to the spec PR. That PR's tree-wide ignoreExtraSpans rule, which this fixture's negative assertions rely on, is in PR 3.

Completes the split: this branch's tree is identical to #2964 apart from a .gitignore entry for local worktrees, which the stack drops.

Test Plan

  • 14 new tests each side: a span per caller-driven getMore, single-span coverage for internally drained cursors, bulk-write cursor nesting, cursors abandoned part-way, change-stream namespaces, and the spec's prose tests 3 and 4.
  • The getMore fixture, which passes unmodified. It caught a real divergence on its first run: the driver had used a single cursor-lifetime span, the reading DRIVERS-3598 rules out.
  • Locally against a replica set: all 196 otel tests across the four PRs pass. A wider sweep of the async suite plus the sync otel modules gives 3,319 passed; the 23 non-passing are Atlas-only suites, mockupdb not being installed, and one timing-sensitive test, and otel reproduces the same set unchanged.
  • just lint clean.

Checklist

Checklist for Author

  • Did you update the changelog (if necessary)?
  • Is there test coverage?
  • Is any followup work tracked in a JIRA ticket? If so, add link(s).

Checklist for Reviewer

  • Does the title of the PR reference a JIRA Ticket?
  • Do you fully understand the implementation? (Would you be comfortable explaining how this code works to someone else?)
  • Is all relevant documentation (README or docstring) updated?

@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from deba5ab to 3406414 Compare August 17, 2026 22:39
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 3406414 to a8961f2 Compare August 17, 2026 22:50
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from a8961f2 to bd799e7 Compare August 17, 2026 23:09
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from bd799e7 to f407469 Compare August 18, 2026 01:40
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from f407469 to 5c8726d Compare August 18, 2026 01:54
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 5c8726d to c89b279 Compare August 18, 2026 02:06
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from c89b279 to 25760c0 Compare August 18, 2026 10:22
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch 2 times, most recently from 09b8a1a to 55f6ad7 Compare August 18, 2026 10:35
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 55f6ad7 to ab27a41 Compare August 18, 2026 10:44
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from ab27a41 to 31efdcf Compare August 18, 2026 10:47
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 31efdcf to 5fddbd6 Compare August 18, 2026 11:06
@blink1073 blink1073 changed the title PYTHON-5947 Add OpenTelemetry operation spans for cursor getMores PYTHON-5993 Add OpenTelemetry operation spans for cursor getMores Aug 18, 2026
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 5fddbd6 to 5387bd4 Compare August 18, 2026 11:18
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 5387bd4 to 4faf2b4 Compare August 18, 2026 11:43
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 4faf2b4 to 8a8720e Compare August 18, 2026 11:50
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from dba0bf0 to e52dbb2 Compare August 21, 2026 15:28
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from e52dbb2 to d53776e Compare August 21, 2026 15:49
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from d53776e to fe696df Compare August 21, 2026 16:01
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from fe696df to 570c135 Compare August 23, 2026 21:02
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 570c135 to 9c40352 Compare August 23, 2026 22:29
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 9c40352 to f386fdf Compare August 26, 2026 16:53
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from f386fdf to 89d2b0e Compare August 26, 2026 19:43
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from c95d6d3 to d39e968 Compare September 1, 2026 10:27
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch 2 times, most recently from 373f78b to dfdd532 Compare September 1, 2026 11:01
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from dfdd532 to 786365a Compare September 1, 2026 16:00
Give each caller-driven getMore an operation span of its own, as the
specification requires: the application may do unrelated work between
batches, so nesting them under the operation that created the cursor would
misrepresent the timing.

A public API call that creates a cursor and drains it itself, such as
list_collection_names or index_information, is the exception. Those mark the
block with internal_cursor_iteration(), and every getMore inside it belongs
to that call's single operation span. The client bulk-write results cursor is
a second exception, reusing the enclosing bulkWrite span rather than creating
spurious siblings.

Change streams deliberately get neither treatment: they can tail
indefinitely, so a span covering the whole lifetime would never end.

Also vendors the getMore spec fixture, the one fixture that needs this
support.
Adds tests/transaction/get_more.yml from the pending spec change, which
covers a cursor iterated inside a transaction started with the core
transaction API: the getMore operation span is a sibling of the find
operation span that created the cursor, and both nest under the
transaction span.

Review feedback on mongodb/specifications#1973 asked for this case as a
unified test rather than a prose test. It passes against the driver
unchanged. The fixture comes from a specification change that is not
merged yet.
Carries the wording from PR 1 forward and corrects it for the behavior
this branch adds: both cursor types pass a span now, and what one covers
is a single caller-driven getMore rather than a run of them.
Cut each to the invariant a reader needs, dropping spec references and
restatements of the code.
The pending spec change introduces $$gte, the lower-bound counterpart to
$$lte, as unified test format schema version 1.29. The OTel getMore
fixtures use it to assert that db.mongodb.cursor_id is non-zero, which
pins the requirement that a getMore records the cursor id it sent rather
than the 0 its reply returns. $$type alone cannot express that, since 0
is a valid int.

Adds _operation_gte and raises the runner's supported schema version to
1.29. Both fixtures come from a specification change that is not merged
yet.
The spec dropped its prose test for the sent cursor id, because the
unified fixtures now assert db.mongodb.cursor_id: { $$gte: 1 }, which
fails a driver that recorded the reply's 0. Its transaction prose test
is renumbered from 4 to 3.

Keeps the sent-cursor-id assertion as a driver test rather than deleting
it: it checks equality with the id actually sent, which a lower bound
cannot express. Renamed so it no longer claims to be a spec prose test.

Also vendors valid-pass/operator-gte.json, the runner reference test for
the new operator. It comes from a specification change that is not merged
yet.
The spec re-added its prose test for this assertion, so the driver test
carries its number again.
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 786365a to 865ce08 Compare September 1, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant