Skip to content

PYTHON-5855 Propagate the W3C traceparent to the server - #3055

Draft
blink1073 wants to merge 5 commits into
PYTHON-5947-otel-5-error-typefrom
PYTHON-5855-traceparent
Draft

blink1073 wants to merge 5 commits into
PYTHON-5947-otel-5-error-typefrom
PYTHON-5855-traceparent

Conversation

@blink1073

@blink1073 blink1073 commented Sep 15, 2026

Copy link
Copy Markdown
Member

PYTHON-5855

Sixth in the OpenTelemetry stack, on top of #3000. Base is PYTHON-5947-otel-5-error-type.

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
5 PYTHON-5947-otel-5-error-type error.type command span attribute
6 PYTHON-5855-traceparent server trace context propagation (this PR)

Implements DRIVERS-3454 (mongodb/specifications#1966). The driver attaches the command span's W3C traceparent to each command as an OP_MSG Payload Type 3 telemetry section, so server spans join the driver's trace as children of the exact command or retry attempt that produced them.

Changes in this PR

  • Added the Payload Type 3 telemetry section {"otel": {"traceparent": "<55-char value>"}} to every Python and C encode path.
  • Created the command span before message encoding so its SpanContext is available for the traceparent.
  • Attached the section only when tracing is enabled, the connection's maxWireVersion is at least 29, and the command span yields a valid traceparent.
  • Propagated unsampled contexts, so the sampling decision does not change whether the section is sent.
  • Omitted the section for sensitive and monitoring commands, which carry no command span.
  • Reserved the section size during batch splitting so a batch cannot exceed maxMessageSizeBytes.
  • Ended a pre-created command span when encoding fails, instead of leaking it.
  • Added unit tests and prose tests 5 through 7 for server span joining, per-attempt parenting, and the auth and monitoring exclusion.

Test Plan

  • Wire-format unit tests in test/test_message.py::TestTelemetrySection assert the type-3 section is last and well-formed on the C and pure-Python encoders, that it is absent without a traceparent, and that batch splitting reserves its size.
  • test/test_message.py plus the otel suites (test_otel.py, test_otel_getmore.py, test_otel_transactions.py, test_open_telemetry_unified.py, async and sync): 267 passed, 37 skipped against a MongoDB 9.1 standalone started with the OpenTelemetry file exporter (OTEL=1).
  • Prose tests 5 through 7 read the server spans exported to OTEL_TRACE_DIR and assert the parent linkage to the driver command spans. They skip when OTEL_TRACE_DIR is unset.
  • ruff and just typing are 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 added this pull request to stack #2995 September 15, 2026 16:36
@blink1073
blink1073 force-pushed the PYTHON-5855-traceparent branch from 8b5305f to 71c8901 Compare September 15, 2026 17:37
@blink1073
blink1073 requested a balanced review from Copilot September 15, 2026 17:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Reauthentication can reuse an ended command span and stale traceparent, while some bulk metadata and authentication tests are incomplete.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds W3C trace-context propagation from PyMongo command spans to MongoDB server spans via OP_MSG telemetry sections.

Changes:

  • Adds Payload Type 3 encoding across Python and C paths.
  • Pre-creates command spans and handles encoding failures.
  • Adds wire-format and server-span integration tests.
File summaries
File Description
pymongo/_otel.py Builds traceparents and telemetry sections.
pymongo/_telemetry.py Supports pre-created command spans.
pymongo/message.py Encodes telemetry sections and reserves batch space.
pymongo/_cmessagemodule.c Adds C encoder support.
pymongo/asynchronous/command_runner.py Creates spans before command encoding.
pymongo/synchronous/command_runner.py Synchronous generated counterpart.
pymongo/asynchronous/cursor_base.py Propagates traceparents for cursor commands.
pymongo/synchronous/cursor_base.py Synchronous generated counterpart.
pymongo/asynchronous/bulk.py Propagates traceparents for collection bulk writes.
pymongo/synchronous/bulk.py Synchronous generated counterpart.
pymongo/asynchronous/client_bulk.py Propagates traceparents for client bulk writes.
pymongo/synchronous/client_bulk.py Synchronous generated counterpart.
test/test_message.py Tests telemetry wire encoding and size reservation.
test/asynchronous/test_otel.py Adds async tracing and server-span tests.
test/test_otel.py Synchronous generated tracing tests.
Review details

Suppressed comments (1)

pymongo/asynchronous/bulk.py:377

  • The pre-created span captured cmd before batch splitting, so it never sees the selected operation documents that write_command adds afterward. This regresses db.query.text for acknowledged collection bulk writes; refresh it from to_send before handing the span to the command runner.
            msg = cast(bytes, msg)
  • Files reviewed: 15/15 changed files
  • Comments generated: 4
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pymongo/asynchronous/bulk.py
Comment thread pymongo/asynchronous/bulk.py Outdated
Comment thread test/asynchronous/test_otel.py Outdated
Comment thread test/asynchronous/test_otel.py
@blink1073
blink1073 force-pushed the PYTHON-5855-traceparent branch 2 times, most recently from 8af1edf to b6f0072 Compare September 15, 2026 19:58
@blink1073
blink1073 requested a balanced review from Copilot September 15, 2026 20:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Trace flags need validation to prevent malformed wire context, and the asynchronous polling tests perform blocking operations.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread pymongo/_otel.py
Comment thread test/asynchronous/test_otel.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The retry prose test must skip environments that do not support the failCommand failpoint.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread test/asynchronous/test_otel.py
Omit the telemetry section when span trace flags exceed one byte, because
":02x" only pads to a minimum width and would push the traceparent past
55 characters.

Make the server-span prose helpers async: offload trace-directory reads
with run_in_executor and await asyncio.sleep between polls. The sync
mirror keeps the blocking forms.
Prose test 6 configures a failpoint but only checked the server version,
so it failed on servers without test commands. Guard it with
require_failCommand_fail_point, matching the other failpoint tests.
@blink1073
blink1073 force-pushed the PYTHON-5855-traceparent branch from 243b7b4 to 046cb84 Compare September 16, 2026 01:57
The spec renumbered the server trace-context prose tests to 7/8/9 after
inserting the error.type tests as 5/6. Rename the methods to match.
The spec numbers the two error.type prose tests 5 and 6, ahead of the
server trace-context tests. Rename the methods to match.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The implementation satisfies the propagation requirements with broad coverage; identified test-name mismatches are non-blocking.

Review details

Suppressed comments (2)

test/asynchronous/test_otel.py:1258

  • The method name labels this as prose test 8, while the docstring and specification define the retry-attempt case as prose test 6. Align the name so -k prose_6 selects the expected coverage.
    async def test_prose_8_one_server_span_per_retry_attempt(self):

test/asynchronous/test_otel.py:1306

  • This is prose test 7 according to the docstring and specification, not prose test 9. The mismatched name makes the auth/monitoring exclusion test difficult to select by its documented number.
    async def test_prose_9_no_trace_context_for_auth_monitoring(self):
  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Balanced

await asyncio.sleep(0.5)

@async_client_context.require_version_min(9, 0)
async def test_prose_7_server_spans_join_driver_trace(self):

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.

This will need to be adjusted after #3000 is merged

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.

2 participants