Skip to content

fix(otel): span id collision execution arn scoping#669

Merged
SilanHe merged 10 commits into
mainfrom
fix/span-id-collision-execution-arn-scoping
Jun 30, 2026
Merged

fix(otel): span id collision execution arn scoping#669
SilanHe merged 10 commits into
mainfrom
fix/span-id-collision-execution-arn-scoping

Conversation

@SilanHe

@SilanHe SilanHe commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Issue #, if available:

Description of changes: We have a bug with nested child execution's spans colliding with parent execution's spans. Since the _X_AMZN_TRACE_ID is propagated on the backend, child invocations are receiving the same _X_AMZN_TRACE_ID as the parent. Since we deterministically generate the spanIds using the operationId, a child invocation will currently have identical operationId and thus spanID as the parent execution leading to collisions because previously emitted spans for the parent are being overwritten.

We amend the deterministic span id generation by generating the spanId using a combination of the durableExecutionArn and the operationId. One quirk this does not solve is that the nested child execution from our "invoke" operation will not be naturally nested under the invoke span in the parent. By design, a child execution does not have any information on its parent execution. However, the child execution will be visible under the same traceId as a separate invocation and lambda function. Since it's the same trace, you'll at least be able to locate the related child invoke.

I'll follow this PR up with integration tests for this case as well as some integration tests changes.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

hsilan and others added 8 commits June 26, 2026 14:12
Derive the otelTraceSampled boolean from SpanContext.traceFlags
(bit 0x01 = W3C sampled flag) and include it in the structured log
context alongside traceId and spanId.
Verify the new otelTraceSampled field appears in structured log output
in both the OTel plugin unit test and the log-enrichment integration
test.
Add a typed PluginOperationStatus const enum to replace the untyped
string status field in OperationInfo. The enum contains all operation
lifecycle states from the AWS SDK (STARTED, READY, PENDING, SUCCEEDED,
FAILED, TIMED_OUT, STOPPED, CANCELLED).

Also convert PluginInvocationStatus and AttemptEndInfoOutcome to const
enums for consistency.
…sion

When parent and child workflows share the same trace context and have
operations at the same position (e.g., both at step 1), the
deriveSpanIdFromOperationId function previously produced identical span
IDs for both. This caused incorrect span parenting where the parent
workflow's step span would be nested under the child workflow's step
span instead of its own invocation span.

The fix adds executionArn as a required parameter to
deriveSpanIdFromOperationId and hashes both executionArn and operationId
together, ensuring unique span IDs per execution even within the same
trace.
@SilanHe
SilanHe marked this pull request as ready for review June 30, 2026 20:20
@SilanHe
SilanHe requested a review from a team June 30, 2026 21:39
@SilanHe
SilanHe merged commit d69289f into main Jun 30, 2026
15 checks passed
@SilanHe
SilanHe deleted the fix/span-id-collision-execution-arn-scoping branch June 30, 2026 22:12
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.

3 participants