Skip to content

[exporter/loadbalancing] Add routing key for OTel tracestate randomness (ot=rv) #49660

Description

@MikeGoldsmith

Component(s)

exporter/loadbalancing

Is your feature request related to a problem? Please describe.

Linked-trace workloads (AI agent conversations, browser sessions, multi-step workflows) produce many traces that form one unit of interest. OTEP 235 anticipated sampling these together via a shared explicit randomness value: "There are circumstances where trace-id randomness is inadequate (for example, sampling a group of traces together); in these cases, an rv value is required." The dynamic_sampling processor honours a producer-set shared ot=rv so every trace in a group gets the same sampling decision (#49311, #49520).

For tail-based decisions this only works if the whole group is visible to one collector instance. Today the loadbalancing exporter can co-locate a single trace (routing_key: traceID), but traces sharing an ot=rv still scatter across backends, so any group-level decision needs cross-node coordination.

Describe the solution you'd like

A new routing_key: randomness that routes by the OTel randomness value:

  • For each span, parse the W3C tracestate with pkg/sampling and use the 14-hex rv value as the routing identifier when present.
  • When rv is absent or the tracestate is unparseable, fall back to sampling.TraceIDToRandomness(traceID), the spec's definition of implicit randomness. Traffic without rv therefore keeps per-trace locality with the same semantics as traceID routing.
  • Consumption path mirrors the existing consumeTracesByID optimisation (per-span key, per-key exporter cache), since spans of one trace always share a key.

Scope is traces-only initially. A counter for present-but-unparseable tracestate would make instrumentation problems visible instead of silently falling back. I'd like to implement this; the change is small and follows the same shape as previous routing key additions.

Describe alternatives you've considered

Enhancing the existing traceID key to honour rv when present, on the argument that rv is the spec-correct randomness the key should hash anyway. Two downsides made me prefer an opt-in key: it silently changes routing on upgrade for any deployment whose traffic already carries ot=rv, and care is needed to avoid changing the hash input for non-rv traffic, which would remap every key on the ring. Open to this direction if maintainers prefer it.

Also considered routing_key: attributes with a session/conversation attribute. This only works when the group key is present as a span/resource attribute on every span, which isn't the case for tracestate-propagated grouping, and it doesn't fall back to trace locality for ungrouped traffic.

Additional context

Related: #49311 (dynamic_sampling alpha tracker), #49520 (honour incoming ot=th/ot=rv), open-telemetry/opentelemetry-specification#2918 (consistent sampling across linked traces). On naming: proposing randomness because the key always routes by the trace randomness value on both the rv and fallback paths; rv (matches the tracestate sub-key) or tracestateRV (matches traceID/streamID casing) would also work if preferred.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions