feat(telemetry): add DeterministicIdGenerator + PendingTraceId for true-root deterministic trace_ids

Add a custom OTel IdGenerator that returns a thread-local pending trace_id on
the SDK no-parent (root) branch and a random one otherwise, plus a PendingTraceId
RAII guard that pins that id for the next forced-root span and asserts on
destruction that it was consumed. Wire the generator into
TracerProviderFactory::Create via its 4-arg overload.

This lets hash-derived spans become true trace roots so they line up into one
trace across nodes. It is installed but dormant on this branch: the caller
(hashSpan) arrives on a later branch (phase-3). GenerateSpanId is always random
and is_random_ is false so the W3C random-trace-id flag is not set on
deterministic ids.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pratik Mankawde
2026-07-21 18:35:00 +01:00
parent 508c91d36c
commit 4d95f455f4
3 changed files with 271 additions and 2 deletions

View File

@@ -20,6 +20,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/telemetry/DeterministicIdGenerator.h>
#include <xrpl/telemetry/DiscardFlag.h>
#include <opentelemetry/context/context.h>
@@ -321,9 +322,15 @@ public:
std::make_shared<trace_sdk::TraceIdRatioBasedSampler>(setup_.samplingRatio);
auto sampler = trace_sdk::ParentBasedSamplerFactory::Create(std::move(rootSampler));
// Create TracerProvider
// Create TracerProvider with a DeterministicIdGenerator. It returns a
// deterministic trace_id when a PendingTraceId is active on the thread,
// else a random one — letting hash-derived roots (introduced on a later
// branch) become true trace roots. Dormant until such a caller exists.
sdkProvider_ = trace_sdk::TracerProviderFactory::Create(
std::move(processor), resourceAttrs, std::move(sampler));
std::move(processor),
resourceAttrs,
std::move(sampler),
std::make_unique<DeterministicIdGenerator>());
// Set as global provider
trace_api::Provider::SetTracerProvider(