Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0ea1b3c
DRIVERS-3598 Specify getMore operation span nesting
blink1073 Aug 11, 2026
158ebc8
DRIVERS-3598 Test getMore span nesting and cursor_id presence
blink1073 Aug 11, 2026
225ecef
DRIVERS-3598 Clarify ignoreExtraSpans applies to nested spans
blink1073 Aug 11, 2026
e2e71cb
DRIVERS-3598 Address review: scope getMore iteration rule and cursor_…
blink1073 Aug 11, 2026
ce36231
DRIVERS-3598 Add db.mongodb.cursor_id to the operation span attributes
blink1073 Aug 11, 2026
00e4d57
DRIVERS-3598 Assert cursor_id on operation spans
blink1073 Aug 11, 2026
21b9e86
DRIVERS-3598 Clarify cursor iteration discriminator and cursor_id omi…
blink1073 Aug 11, 2026
0cbe9bf
DRIVERS-3598 Enable tracing via client option in prose test 3
blink1073 Aug 12, 2026
5dfdde1
DRIVERS-3598 Assert sent vs returned cursor id in prose test 3
blink1073 Aug 12, 2026
b20f0e9
DRIVERS-3598 Tighten getMore and cursor_id spec prose
blink1073 Aug 12, 2026
3bc6022
DRIVERS-3598 Shorten ignoreExtraSpans wording
blink1073 Aug 12, 2026
87dbfed
DRIVERS-3598 Add prose test for getMore inside a transaction
blink1073 Aug 12, 2026
2eb1baf
Merge upstream/master into DRIVERS-3598
blink1073 Aug 17, 2026
d679974
DRIVERS-3598 Cover the core transaction API with a unified test
blink1073 Aug 18, 2026
4bdb800
DRIVERS-3598 Add the $$gte operator and assert a non-zero cursor id
blink1073 Aug 26, 2026
9d1a9c8
DRIVERS-3598 Version the ignoreExtraSpans clarification under 1.29
blink1073 Aug 26, 2026
1ca0201
DRIVERS-3598 Address review: killCursors spans, gte reference test
blink1073 Aug 27, 2026
dff2a87
DRIVERS-3598 Require 4.4 or later for the convenient transaction pros…
blink1073 Aug 27, 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
63 changes: 61 additions & 2 deletions source/open-telemetry/open-telemetry.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,35 @@ When a user commits or aborts a transaction with `commitTransaction` or `abortTr
In case of `withTransaction` operation spans for operations that are executed inside the callbacks SHOULD be nested into
the `withTransaction` span.

##### Cursor Iteration (`getMore`)

If the driver does not expose the cursor to the caller, but iterates it internally to produce the return value of one
public API call (e.g., a `find` helper returning an array of all matching documents), the driver MUST NOT create
additional operation spans. Every `getMore` command span for that call MUST be nested under the call's single operation
span.

If the driver returns the cursor to the caller and the caller drives iteration, the driver MUST create a new operation
span for each `getMore` it sends. The span MUST be created within the current span of the host application and MUST be
named according to [Operation Span Name](#operation-span-name): `getMore db.collection_name` for a cursor over a
collection, or `getMore db` when the cursor targets no specific collection (e.g., a cursor from `listCollections`), per
[db.collection.name](#dbcollectionname). The `getMore` command span MUST be nested under it, per
[Instrumenting Server Commands](#instrumenting-server-commands).

This operation span MUST NOT be nested under the operation span of the command that created the cursor. A host
application may do unrelated work between batches, and nesting each `getMore` under the cursor-creating operation would
attribute that work to the original operation. Ordinary nesting still applies otherwise. A cursor iterated inside a
`withTransaction` callback nests into the `withTransaction` span, and a cursor iterated inside a transaction started
with the core transaction API nests into the pseudo operation `transaction` span.

Each `getMore` operation span MUST be finished once its command completes. No span is scoped to a cursor's lifetime, so
a cursor that is never exhausted (e.g., a tailable cursor) leaves nothing unfinished.

A `getMore` is not retryable, but a change stream may resume after one fails. A resume MUST NOT extend the failed
`getMore` operation span: drivers MUST finish that span with its error, and the `aggregate` and `getMore` commands that
re-establish the cursor MUST each be nested under new operation spans. Drivers MUST NOT create an operation span for the
`killCursors` a resume sends; it is internal cleanup rather than a public API call, so its command span is created
within whatever span is current.

##### Operation Span Name

The span name SHOULD be:
Expand Down Expand Up @@ -163,6 +192,7 @@ Spans SHOULD have the following attributes:
| `db.collection.name` | `string` | The collection being accessed within the database stated in `db.namespace` | Required if available |
| `db.operation.name` | `string` | The name of the driver operation being executed | Required |
| `db.operation.summary` | `string` | Equivalent to span name | Required |
| `db.mongodb.cursor_id` | `int64` | If a cursor is created or used in the operation (see below) | Conditional |

Not all attributes are available at the moment of span creation. Drivers need to add attributes at later stages, which
requires an operation span to be available throughout the complete operation lifecycle.
Expand Down Expand Up @@ -198,6 +228,16 @@ Examples:
- `abortTransaction` → *omitted*
- client `bulkWrite` → *omitted*

<span id="operation-cursor-id"></span>

###### db.mongodb.cursor_id

If the operation creates a cursor, or operates on a single existing cursor, the `cursor_id` attribute MUST be added to
the operation span, following the same rules as the command span attribute of the same name, including its omissions:
never a literal `0`, and never for a command that may operate on several cursors at once, such as `killCursors` (see
[db.mongodb.cursor_id](#command-cursor-id)). When the driver iterates a cursor internally, the value is the id of the
cursor the operation created; for a caller-driven `getMore`, it is the id the driver sent.

##### Exceptions

If the driver operation fails with an exception, drivers MUST record an exception to the current operation span. This
Expand Down Expand Up @@ -246,7 +286,7 @@ Spans SHOULD have the following attributes:
| `db.mongodb.server_connection_id` | `int64` | Server connection id | Required if available |
| `db.mongodb.driver_connection_id` | `int64` | Local connection id | Required if available |
| `db.query.text` | `string` | Database command that was sent to the server. Content should be equivalent to the `document` field of the CommandStartedEvent of the command monitoring. | Conditional |
| `db.mongodb.cursor_id` | `int64` | If a cursor is created or used in the operation | Required if available |
| `db.mongodb.cursor_id` | `int64` | If a cursor is created or used in the command (see below) | Conditional |
| `db.mongodb.lsid` | `string` | Logical session id | Required if available |
| `db.mongodb.txn_number` | `int64` | Transaction number | Required if available |

Expand Down Expand Up @@ -308,9 +348,22 @@ added and truncated to the provided value (similar to the Logging specification)
On the `MongoClient` level this configuration can be implemented with a `MongoClient` option, for example,
`tracing.query_text_max_length`.

<span id="command-cursor-id"></span>

###### db.mongodb.cursor_id

If the command returns a cursor, or uses a cursor, the `cursor_id` attribute SHOULD be added.
If the command creates a cursor (e.g., `find`, `aggregate`, `listIndexes`) and the server returns a non-zero cursor id,
the `cursor_id` attribute MUST be added.

If the command operates on a single existing cursor (e.g., `getMore`), the attribute MUST be added, holding the cursor
id the driver sent. It MUST still be added when the reply returns a cursor id of `0` to signal the cursor is now
exhausted; the id the command operated on is the one worth recording.

If a command may operate on several cursors at once (e.g., `killCursors`, whose `cursors` field is an array), the
attribute MUST be omitted: it is a single `int64` and has no defined value for such a command.

A cursor id of `0` means no server-side cursor remains. Drivers MUST NOT add the attribute with a value of `0`, and MUST
omit it when a cursor-creating command's reply returns `0`.

##### Exceptions

Expand Down Expand Up @@ -357,6 +410,7 @@ The OpenTelemetry specification covers all driver operations including but not l
| `dropCollection` | [tests/operation/drop_collection.yml](tests/operation/drop_collection.yml) |
| `dropIndexes` | [tests/operation/drop_indexes.yml](tests/operation/drop_indexes.yml) |
| `find` | [tests/operation/find.yml](tests/operation/find.yml) |
| `getMore` | [tests/operation/get_more.yml](tests/operation/get_more.yml) |
| `listCollections` | [tests/operation/list_collections.yml](tests/operation/list_collections.yml) |
| `listDatabases` | [tests/operation/list_databases.yml](tests/operation/list_databases.yml) |
| `listIndexes` | [tests/operation/list_indexes.yml](tests/operation/list_indexes.yml) |
Expand Down Expand Up @@ -425,6 +479,11 @@ A URI options can be added later if we realise our users need it, while the oppo

## Changelog

- 2026-08-11: Specified that each `getMore` command is nested under its own new operation span, sibling to the operation
span of the command that created the cursor, when the caller drives cursor iteration. Specified that
`db.mongodb.cursor_id` MUST be added to operation spans and to command spans that create a cursor with a non-zero id
or that operate on a single existing cursor, and MUST be omitted rather than set to `0` when no server-side cursor
remains.
- 2026-07-31: Allowed the `update` test to accept `multi` and `upsert` at their default values, and added `initialData`
to the operation tests that create or modify collections.
- 2026-06-16: Clarified that the `db.query.text` attribute should be serialized to Relaxed Extended JSON.
Expand Down
17 changes: 17 additions & 0 deletions source/open-telemetry/tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,20 @@ expectTracingMessages:
7. Create a new `MongoClient`.
8. Perform the same database operation.
9. Assert that the emitted tracing span does not include the `db.query.text` attribute.

*Test 3: `getMore` inside a `withTransaction` callback nests under the transaction span*

This test covers the convenient transaction API. The core transaction API case is covered by the unified test
[tests/transaction/get_more.yml](transaction/get_more.yml).

This test requires a replica set or a sharded cluster running server version 4.4 or later, matching the existing
convenient transaction API fixture [tests/transaction/convenient.yml](transaction/convenient.yml).

1. Create a `MongoClient` with tracing enabled.
2. Insert three documents into a test collection.
3. Start a session and call `withTransaction`. In the callback, create a cursor over that collection with `find` and a
`batchSize` of `2`, then iterate the cursor until it is exhausted. This sends exactly one `getMore` inside the
transaction.
4. Assert that a `transaction` span was emitted, and that both the `find` operation span and the `getMore` operation
span are nested directly under it.
5. Assert that the `getMore` operation span is a sibling of the `find` operation span, and is not nested under it.
Loading
Loading