Skip to content

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

Draft
blink1073 wants to merge 1 commit 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 1 commit 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)

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
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.
@blink1073
blink1073 force-pushed the PYTHON-5947-otel-4-getmore branch from 8a8720e to d6b1d17 Compare August 18, 2026 12:02
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