Repository navigation
feat(telemetry): propagate OTel baggage context in Python [replica of harness-sdk PR 4840] - #31
poshinchen wants to merge 18 commits into
Conversation
Co-authored-by: Strandly (The Agent) <strands-agents+strandly@amazon.com>
poshinchen
left a comment
There was a problem hiding this comment.
Strandly v4-reason (optimized) review — run af1746, Opus 4.8
Assessment: comment
Assessment: Comment
The feature is well-scoped with good docs and a strong set of concurrency/nesting isolation tests. My main blocking concern is confirming the OTel context token is detached on every exit path, plus a correctness question about forwarding a sequence of predicates to BaggageSpanProcessor.
Review Categories
- Correctness: Verify
context_api.detach(baggage_token)runs in afinallyfor all paths (success/exception/cancellation); confirm sequence-of-predicates is actually supported byBaggageSpanProcessorrather than silently passed through. - API: New public constructor param and
setup_baggage_processor()method — confirm API bar-raising review /api/needs-reviewlabel and thatbaggage_attributesvstrace_attributesnaming is clear. - Testing: Sequence predicate path is only covered via mocks; an end-to-end test would strengthen it.
- Validation:
baggage_attributesbypasses the type filtering applied totrace_attributes; document or justify the asymmetry.
Nice work on the interleaved-agents and nested-override tests — those cover the tricky context-propagation cases.
| messages = await self._convert_prompt_to_messages(prompt) | ||
|
|
||
| self.trace_span = self._start_agent_trace_span(messages) | ||
| baggage_ctx = context_api.get_current() |
There was a problem hiding this comment.
[Critical]
Issue: context_api.attach(baggage_ctx) returns a token that must be detached with context_api.detach(baggage_token) in a finally block, otherwise the baggage context leaks onto the calling task/thread after the invocation ends. The diff shows the attach and the opening try:, but the restoration is not visible here.
Suggestion: Confirm the try: opened on the next line has a matching finally: context_api.detach(baggage_token) that runs on every exit path (success, exception, cancellation). The nested-restore test exercises the happy path; please also verify detach runs when _run_loop raises.
| load_tools_from_directory: bool = False, | ||
| trace_attributes: Mapping[str, AttributeValue] | None = None, | ||
| *, | ||
| baggage_attributes: Mapping[str, str] | None = None, |
There was a problem hiding this comment.
[Important]
Issue: baggage_attributes adds a new public constructor parameter and setup_baggage_processor() adds a new public method on StrandsTelemetry — both are customer-facing API surface. The PR description documents usage well, but I don't see confirmation that an API review / api/needs-review label was applied.
Suggestion: Please confirm this change has gone through API bar-raising review (or add the api/needs-review label). Worth validating that baggage_attributes is the right name/level of abstraction vs. the existing trace_attributes, since the two are easy to confuse.
| logger.info("Enabling baggage span processor") | ||
| predicate = ALLOW_ALL_BAGGAGE_KEYS if baggage_key_predicate is None else baggage_key_predicate | ||
| self.tracer_provider.add_span_processor(BaggageSpanProcessor(predicate)) | ||
| except Exception as e: |
There was a problem hiding this comment.
[Suggestion]
Issue: setup_baggage_processor accepts BaggageKeyPredicates (single predicate or a sequence), but BaggageSpanProcessor(predicate) is called with the value passed straight through. It's not obvious from this diff that BaggageSpanProcessor natively accepts a sequence of predicates — if it only accepts a single callable, passing a list would silently misbehave (a non-empty list is always truthy).
Suggestion: Verify BaggageSpanProcessor supports a sequence argument. If it only accepts a single predicate, combine the sequence here (e.g. lambda k: any(p(k) for p in predicates)) rather than forwarding the list unchanged. The sequence unit test uses a mock, so it wouldn't catch this.
| ): | ||
| self.trace_attributes[k] = v | ||
|
|
||
| self.baggage_attributes: dict[str, str] = dict(baggage_attributes) if baggage_attributes else {} |
There was a problem hiding this comment.
[Suggestion]
Issue: baggage_attributes is typed Mapping[str, str] and copied verbatim into OTel baggage, unlike trace_attributes which is filtered to safe scalar types just above. Non-string values passed by a caller (despite the hint, hints aren't enforced at runtime) would flow into set_baggage and ultimately onto the baggage header.
Suggestion: Consider whether any validation/coercion is warranted here, or document that values must be strings. At minimum this asymmetry with trace_attributes handling is worth a brief comment so future readers know the lack of filtering is intentional.
| telemetry = StrandsTelemetry() | ||
| telemetry.tracer_provider = mock_tracer_provider.return_value | ||
| result = telemetry.setup_baggage_processor(baggage_key_predicate) | ||
|
|
There was a problem hiding this comment.
[Suggestion]
Issue: The sequence parametrization asserts BaggageSpanProcessor.assert_called_once_with(baggage_key_predicate) with the processor fully mocked, so it only verifies pass-through. It does not prove that a sequence of predicates actually produces OR-matching behavior end-to-end.
Suggestion: Add one integration-style test (like test_baggage_attributes_stamped_on_agent_span) using a real BaggageSpanProcessor with a sequence predicate to confirm matching semantics, which would also surface the pass-through concern raised in config.py.
|
Live Strandly's actual comments on the original PR 4840 (sanitized copy: mentions escaped, links backticked) Review (CHANGES_REQUESTED):
Review (COMMENTED):
Review (CHANGES_REQUESTED):
Review (COMMENTED):
Review (APPROVED):
Review (CHANGES_REQUESTED):
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
Inline at
|
Documentation Preview FailedThe documentation deployment encountered an error. Please check the deployment logs for more details. |
Replica of
https://github.com/strands-agents/harness-sdk/pull/4840(backticked: no cross-reference). Below: the v4-reason optimized review and a sanitized copy of live Strandly's actual comments.