From 4f4b4dd199b40a4bb08f0146818d2d3d004b47d9 Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Tue, 28 Apr 2026 12:44:31 +0100 Subject: [PATCH] refactor(telemetry): replace txSpan with generic hashSpan factory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace SpanGuard::txSpan(prefix, name, hash) with the generic SpanGuard::hashSpan(TraceCategory, name, hash) that accepts a TraceCategory parameter instead of hardcoding Transactions. This enables reuse for consensus round spans (Phase 4) and any future subsystem needing deterministic cross-node trace correlation via hash-derived trace IDs. Both overloads are replaced: - hashSpan(cat, name, hash, size) — standalone with random span_id - hashSpan(cat, name, hash, size, parentSpanId, parentSize, flags) — with remote parent from protobuf context propagation Add full span name constants (tx_span::receive, tx_span::process) to TxSpanNames.h following the ConsensusSpanNames.h pattern. Co-Authored-By: Claude Opus 4.6 (1M context) --- include/xrpl/telemetry/SpanGuard.h | 39 +++++++++++++++-------------- src/libxrpl/telemetry/SpanGuard.cpp | 23 ++++++++--------- src/xrpld/app/misc/TxSpanNames.h | 5 ++++ src/xrpld/telemetry/TxTracing.h | 12 +++++---- 4 files changed, 43 insertions(+), 36 deletions(-) diff --git a/include/xrpl/telemetry/SpanGuard.h b/include/xrpl/telemetry/SpanGuard.h index 79d6c7659a..3cc11f7654 100644 --- a/include/xrpl/telemetry/SpanGuard.h +++ b/include/xrpl/telemetry/SpanGuard.h @@ -17,8 +17,8 @@ | + span(cat, prefix, name) [static] | | + childSpan(name) : SpanGuard | | + linkedSpan(name) : SpanGuard | - | + txSpan(prefix, name, hash) [static] | - | + txSpan(prefix, name, hash, parent) [static] | + | + hashSpan(cat, name, hash) [static] | + | + hashSpan(cat, name, hash, parent) [static] | | + captureContext() : SpanContext | | + setAttribute(key, value) | | + setOk() / setError(desc) | @@ -239,30 +239,31 @@ public: [[nodiscard]] static SpanGuard linkedSpan(std::string_view name, SpanContext const& linkCtx); - // --- Transaction span with hash-derived trace ID ------------------- + // --- Hash-derived span (category-gated) ----------------------------- - /** Create a span whose trace_id is derived from a transaction hash. - trace_id = hashData[0:16], span_id = random. All nodes handling - the same transaction independently produce spans under the same - trace, enabling cross-node correlation without context propagation. - @param prefix Span name prefix (e.g. "tx"). - @param name Span name suffix (e.g. "receive"). + /** Create a span whose trace_id is derived from arbitrary hash data. + trace_id = hashData[0:16], span_id = random. Gated by the given + TraceCategory. All nodes using the same hash independently produce + spans under the same trace_id, enabling cross-node correlation + without context propagation. + @param cat Trace subsystem category. + @param name Full span name (e.g. "tx.receive"). @param hashData Pointer to at least 16 bytes of hash data. @param hashSize Size of the hash buffer (must be >= 16). */ static SpanGuard - txSpan( - std::string_view prefix, + hashSpan( + TraceCategory cat, std::string_view name, std::uint8_t const* hashData, std::size_t hashSize); - /** Create a span with hash-derived trace_id and a remote parent. + /** Create a hash-derived span with a remote parent. trace_id = hashData[0:16], parent span_id from protobuf context propagation. Produces a child span of the sender's span while sharing the deterministic trace_id. - @param prefix Span name prefix. - @param name Span name suffix. + @param cat Trace subsystem category. + @param name Full span name. @param hashData Pointer to at least 16 bytes of hash data. @param hashSize Size of the hash buffer (must be >= 16). @param parentSpanId Pointer to 8 bytes of parent span ID. @@ -270,8 +271,8 @@ public: @param traceFlags Trace flags from remote context. */ static SpanGuard - txSpan( - std::string_view prefix, + hashSpan( + TraceCategory cat, std::string_view name, std::uint8_t const* hashData, std::size_t hashSize, @@ -393,13 +394,13 @@ public: } [[nodiscard]] static SpanGuard - txSpan(std::string_view, std::string_view, std::uint8_t const*, std::size_t) + hashSpan(TraceCategory, std::string_view, std::uint8_t const*, std::size_t) { return {}; } [[nodiscard]] static SpanGuard - txSpan( - std::string_view, + hashSpan( + TraceCategory, std::string_view, std::uint8_t const*, std::size_t, diff --git a/src/libxrpl/telemetry/SpanGuard.cpp b/src/libxrpl/telemetry/SpanGuard.cpp index 3d3f52ca29..dd5997a2b5 100644 --- a/src/libxrpl/telemetry/SpanGuard.cpp +++ b/src/libxrpl/telemetry/SpanGuard.cpp @@ -20,9 +20,10 @@ #ifdef XRPL_ENABLE_TELEMETRY +#include + #include #include -#include #include #include @@ -232,11 +233,11 @@ SpanGuard::linkedSpan(std::string_view name, SpanContext const& linkCtx) opts))); } -// ===== Transaction span with hash-derived trace ID ======================== +// ===== Hash-derived span (category-gated) ================================== SpanGuard -SpanGuard::txSpan( - std::string_view prefix, +SpanGuard::hashSpan( + TraceCategory cat, std::string_view name, std::uint8_t const* hashData, std::size_t hashSize) @@ -244,7 +245,7 @@ SpanGuard::txSpan( if (hashSize < 16) return {}; auto* tel = Telemetry::getInstance(); - if (!tel || !tel->isEnabled() || !tel->shouldTraceTransactions()) + if (!tel || !tel->isEnabled() || !isCategoryEnabled(*tel, cat)) return {}; otel_trace::TraceId traceId(opentelemetry::nostd::span(hashData, 16)); @@ -262,13 +263,12 @@ SpanGuard::txSpan( opentelemetry::nostd::shared_ptr( new otel_trace::DefaultSpan(syntheticCtx))); - auto fullName = std::string(prefix) + "." + std::string(name); - return SpanGuard(std::make_unique(tel->startSpan(fullName, parentCtx))); + return SpanGuard(std::make_unique(tel->startSpan(std::string(name), parentCtx))); } SpanGuard -SpanGuard::txSpan( - std::string_view prefix, +SpanGuard::hashSpan( + TraceCategory cat, std::string_view name, std::uint8_t const* hashData, std::size_t hashSize, @@ -279,7 +279,7 @@ SpanGuard::txSpan( if (hashSize < 16 || parentSpanSize != 8) return {}; auto* tel = Telemetry::getInstance(); - if (!tel || !tel->isEnabled() || !tel->shouldTraceTransactions()) + if (!tel || !tel->isEnabled() || !isCategoryEnabled(*tel, cat)) return {}; otel_trace::TraceId traceId(opentelemetry::nostd::span(hashData, 16)); @@ -295,8 +295,7 @@ SpanGuard::txSpan( opentelemetry::nostd::shared_ptr( new otel_trace::DefaultSpan(combinedCtx))); - auto fullName = std::string(prefix) + "." + std::string(name); - return SpanGuard(std::make_unique(tel->startSpan(fullName, parentCtx))); + return SpanGuard(std::make_unique(tel->startSpan(std::string(name), parentCtx))); } // ===== Context capture ===================================================== diff --git a/src/xrpld/app/misc/TxSpanNames.h b/src/xrpld/app/misc/TxSpanNames.h index 1401e10c2a..c4d79ca960 100644 --- a/src/xrpld/app/misc/TxSpanNames.h +++ b/src/xrpld/app/misc/TxSpanNames.h @@ -35,6 +35,11 @@ inline constexpr auto receive = makeStr("receive"); inline constexpr auto process = makeStr("process"); } // namespace op +// ===== Full span names (prefix.op) ========================================= + +inline constexpr auto receive = join(prefix::tx, op::receive); +inline constexpr auto process = join(prefix::tx, op::process); + // ===== Attribute keys ====================================================== namespace attr { diff --git a/src/xrpld/telemetry/TxTracing.h b/src/xrpld/telemetry/TxTracing.h index 9cb0f296a6..e466c45a6c 100644 --- a/src/xrpld/telemetry/TxTracing.h +++ b/src/xrpld/telemetry/TxTracing.h @@ -33,9 +33,9 @@ txReceiveSpan(uint256 const& txID, [[maybe_unused]] protocol::TMTransaction cons auto const& tc = msg.trace_context(); if (tc.has_span_id() && tc.span_id().size() == 8) { - return SpanGuard::txSpan( - tx_span::prefix::tx, - tx_span::op::receive, + return SpanGuard::hashSpan( + TraceCategory::Transactions, + tx_span::receive, txID.data(), txID.bytes, reinterpret_cast(tc.span_id().data()), @@ -45,7 +45,8 @@ txReceiveSpan(uint256 const& txID, [[maybe_unused]] protocol::TMTransaction cons } } #endif - return SpanGuard::txSpan(tx_span::prefix::tx, tx_span::op::receive, txID.data(), txID.bytes); + return SpanGuard::hashSpan( + TraceCategory::Transactions, tx_span::receive, txID.data(), txID.bytes); } /** Create a "tx.process" span for transaction processing in NetworkOPs. @@ -54,7 +55,8 @@ txReceiveSpan(uint256 const& txID, [[maybe_unused]] protocol::TMTransaction cons inline SpanGuard txProcessSpan(uint256 const& txID) { - return SpanGuard::txSpan(tx_span::prefix::tx, tx_span::op::process, txID.data(), txID.bytes); + return SpanGuard::hashSpan( + TraceCategory::Transactions, tx_span::process, txID.data(), txID.bytes); } } // namespace telemetry