From 28a8ab144b6706ae82ddc37560463178c2f72910 Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Wed, 22 Jul 2026 22:58:17 +0100 Subject: [PATCH] feat(telemetry): correlate ledger.acquire outcome log via span activation Co-Authored-By: Claude Opus 4.8 (1M context) --- .../09-data-collection-reference.md | 6 +-- src/xrpld/app/ledger/detail/InboundLedger.cpp | 46 ++++++++++++------- 2 files changed, 32 insertions(+), 20 deletions(-) diff --git a/OpenTelemetryPlan/09-data-collection-reference.md b/OpenTelemetryPlan/09-data-collection-reference.md index cc8de36148..f3edaf079a 100644 --- a/OpenTelemetryPlan/09-data-collection-reference.md +++ b/OpenTelemetryPlan/09-data-collection-reference.md @@ -152,9 +152,9 @@ later spans — the `stage` attribute identifies where it stopped. > coroutine across `yield()` and resumes on whatever thread the scheduler picks. > RPC, consensus, and transaction spans therefore keep per-line log-trace > correlation, and their scopes are safe across coroutine yields. Job-handoff -> spans — transaction apply and receive, and consensus accept — are activated -> inside their worker bodies rather than at enqueue, so each worker's log lines -> carry the span's trace context. +> spans — transaction apply and receive, consensus accept, and ledger acquire — +> are activated inside their worker bodies rather than at enqueue, so each +> worker's log lines carry the span's trace context. **Where to find**: Tempo → TraceQL: `{resource.service.name="xrpld" && name=~"tx.process|tx.receive"}` or, for the apply pipeline: `{resource.service.name="xrpld" && name=~"tx.preflight|tx.preclaim|tx.transactor"}` diff --git a/src/xrpld/app/ledger/detail/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp index bb0b2ee8e0..2b47f92244 100644 --- a/src/xrpld/app/ledger/detail/InboundLedger.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedger.cpp @@ -453,25 +453,37 @@ InboundLedger::done() touch(); // Finalize the acquire span with the outcome, timeout count, and peer - // count, then end it (reset) so its duration is exported. - if (acquireSpan_ && *acquireSpan_) + // count. Keep it active as the ambient context across the finalize and + // the outcome log below so that log line carries the span's trace_id. + // The activation is non-owning; acquireSpan_ still owns the span. The + // activation pops at the end of this block (restoring the prior context) + // while acquireSpan_ is still alive, then reset() ends the span. { - using namespace telemetry; - acquireSpan_->setAttribute( - ledger_span::attr::outcome, - failed_ ? std::string_view(ledger_span::val::failed) - : std::string_view(ledger_span::val::complete)); - acquireSpan_->setAttribute(ledger_span::attr::timeouts, static_cast(timeouts_)); - acquireSpan_->setAttribute( - ledger_span::attr::peerCount, static_cast(getPeerCount())); - } - acquireSpan_.reset(); + auto acquireActivation = (acquireSpan_ && *acquireSpan_) ? acquireSpan_->activate() + : telemetry::ScopedActivation{}; + if (acquireSpan_ && *acquireSpan_) + { + using namespace telemetry; + acquireSpan_->setAttribute( + ledger_span::attr::outcome, + failed_ ? std::string_view(ledger_span::val::failed) + : std::string_view(ledger_span::val::complete)); + acquireSpan_->setAttribute( + ledger_span::attr::timeouts, static_cast(timeouts_)); + acquireSpan_->setAttribute( + ledger_span::attr::peerCount, static_cast(getPeerCount())); + } - JLOG(journal_.debug()) << "Acquire " << hash_ << (failed_ ? " fail " : " ") - << ((timeouts_ == 0) - ? std::string() - : (std::string("timeouts:") + std::to_string(timeouts_) + " ")) - << stats_.get(); + JLOG(journal_.debug()) << "Acquire " << hash_ << (failed_ ? " fail " : " ") + << ((timeouts_ == 0) ? std::string() + : (std::string("timeouts:") + + std::to_string(timeouts_) + " ")) + << stats_.get(); + // acquireActivation pops here, before the span is ended below. + } + // End the acquire span after its outcome log. Unconditional so the span + // never leaks even when it was inactive. + acquireSpan_.reset(); XRPL_ASSERT(complete_ || failed_, "xrpl::InboundLedger::done : complete or failed");