From 0aa76527dbc6c0c86e8056b3ade6522538ec3cf5 Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Sat, 25 Jul 2026 20:26:40 +0100 Subject: [PATCH] feat(telemetry): join ledger.acquire into the per-ledger trace Completes the join left open when the acquire and consensus work landed in parallel. The acquire span now derives its trace id from the ledger hash it already records, so a fetch shares one trace with that ledger's validation, acceptance and store, and its three phase children inherit the same id. Reading one trace now answers the whole question for a slow ledger: whether the data was slow to arrive, slow to be accepted, or slow to persist. The acquire span stays an optional member of the join group, for the reason its own entry already gives: a healthy cluster agreeing from genesis rarely back-fills, so the span need not appear on every run. Co-Authored-By: Claude Opus 5 (1M context) --- src/xrpld/app/ledger/detail/InboundLedger.cpp | 10 ++++++++-- src/xrpld/app/ledger/detail/LedgerSpanNames.h | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/xrpld/app/ledger/detail/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp index ed2aef14f4..5da372f319 100644 --- a/src/xrpld/app/ledger/detail/InboundLedger.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedger.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include @@ -111,8 +110,15 @@ InboundLedger::init(ScopedLockType& collectionLock) // acquireSpan_ is emplaced here but reset() on a JtLedgerData worker // thread. A SpanGuard is thread-free (owns no thread-local Scope), so it // can be created here and destroyed on the worker with no scope to strip. + // hashSpan, not span: the trace id is derived from hash_[0:16], so this + // acquire lands in the same trace as the ledger.validate, + // ledger.store and consensus.validation.accept spans for the same + // ledger, which run on other threads. One trace then shows whether a + // slow ledger was slow to fetch, to be accepted, or to be stored. The + // phase children below inherit this trace id automatically. acquireSpan_.emplace( - SpanGuard::span(TraceCategory::Ledger, seg::ledger, ledger_span::op::acquire)); + SpanGuard::hashSpan( + TraceCategory::Ledger, ledger_span::acquireFull, hash_.data(), hash_.kBytes)); if (*acquireSpan_) { // The hash is the one identity known at every acquire's start (a diff --git a/src/xrpld/app/ledger/detail/LedgerSpanNames.h b/src/xrpld/app/ledger/detail/LedgerSpanNames.h index c8abdfd0be..9449593e44 100644 --- a/src/xrpld/app/ledger/detail/LedgerSpanNames.h +++ b/src/xrpld/app/ledger/detail/LedgerSpanNames.h @@ -65,6 +65,13 @@ inline constexpr auto txset = makeStr("txset"); * names a dashboard and TraceQL query match on, so they must stay stable and * unambiguous rather than reading as a further-nested `as.tree`. */ +/** + * The parent acquire span's full name. Named here rather than composed at the + * call site because it is passed to hashSpan(), which takes one complete name, + * and because the phase names below are built from the same two segments. + */ +inline constexpr auto acquireFull = join(seg::ledger, op::acquire); + inline constexpr auto acquireHeader = join(join(seg::ledger, op::acquire), makeStr("header")); inline constexpr auto acquireAsTree = join(join(seg::ledger, op::acquire), makeStr("astree")); inline constexpr auto acquireTxTree = join(join(seg::ledger, op::acquire), makeStr("txtree"));