From 937d11d7c3ce54e0648ecc5d90124314e07c2093 Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Wed, 13 May 2026 14:40:57 +0100 Subject: [PATCH 1/5] fix(telemetry): default tx span attrs on receive path Set defaults for tx_span::attr::suppressed (false) and tx_span::attr::status ("new") immediately after creating the txReceive span. Without defaults, spans whose suppressed/status attributes would only be set in the HashRouter-suppressed branch lacked these attributes entirely, producing incomplete span data in downstream stores. The suppressed branch still overrides these when the transaction has already been seen via HashRouter. --- src/xrpld/overlay/detail/PeerImp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 8b8ce7877c..1f19847cda 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -1448,6 +1448,11 @@ PeerImp::handleTransaction( span->setAttribute(tx_span::attr::peerId, static_cast(id_)); if (auto const version = getVersion(); !version.empty()) span->setAttribute(tx_span::attr::peerVersion, version.c_str()); + // Set defaults for conditional attributes so they are always present + // on the span. The suppressed path overrides these when the + // transaction has already been seen via HashRouter. + span->setAttribute(tx_span::attr::suppressed, false); + span->setAttribute(tx_span::attr::status, "new"); // Charge strongly for attempting to relay a txn with tfInnerBatchTxn // LCOV_EXCL_START From 7a854ccad2894f7ead7974e3e9edf782d3211359 Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Wed, 13 May 2026 15:54:13 +0100 Subject: [PATCH 2/5] =?UTF-8?q?refactor(telemetry):=20simplify=20attr=20na?= =?UTF-8?q?ming=20on=20phase-1c=20=E2=80=94=20drop=20xrpl..=20pref?= =?UTF-8?q?ix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Drop xrpl.rpc.* prefix from per-span attrs (command, version). - Qualify collision-prone fields: role -> rpc_role/grpc_role, status -> rpc_status/grpc_status. - Rename payload_size -> request_payload_size for cross-domain clarity. - Simplify link.type -> link_type (bare name, no join). - Update convention doc in SpanNames.h to reflect new naming rules. - Update telemetry.md doc with renamed attr keys. Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/build/telemetry.md | 10 ++++----- include/xrpl/telemetry/SpanGuard.h | 4 ++-- include/xrpl/telemetry/SpanNames.h | 11 ++++++---- src/xrpld/app/main/GrpcSpanNames.h | 16 ++++++-------- src/xrpld/rpc/detail/RPCHandler.cpp | 6 +++--- src/xrpld/rpc/detail/RpcSpanNames.h | 30 ++++++++++++-------------- src/xrpld/rpc/detail/ServerHandler.cpp | 4 ++-- 7 files changed, 40 insertions(+), 41 deletions(-) diff --git a/docs/build/telemetry.md b/docs/build/telemetry.md index e8d7fb2dd5..1e6e715353 100644 --- a/docs/build/telemetry.md +++ b/docs/build/telemetry.md @@ -185,15 +185,15 @@ Traced RPC operations produce a span hierarchy like: ``` rpc.request - └── rpc.command.server_info (xrpl.rpc.command=server_info, xrpl.rpc.status=success) + └── rpc.command.server_info (command=server_info, rpc_status=success) ``` Each span includes attributes: -- `xrpl.rpc.command` — the RPC method name -- `xrpl.rpc.version` — API version -- `xrpl.rpc.role` — `admin` or `user` -- `xrpl.rpc.status` — `success` or `error` +- `command` — the RPC method name +- `version` — API version +- `rpc_role` — `admin` or `user` +- `rpc_status` — `success` or `error` ## Running Tests diff --git a/include/xrpl/telemetry/SpanGuard.h b/include/xrpl/telemetry/SpanGuard.h index 6718052219..6489e31c3e 100644 --- a/include/xrpl/telemetry/SpanGuard.h +++ b/include/xrpl/telemetry/SpanGuard.h @@ -50,7 +50,7 @@ auto span = SpanGuard::span( TraceCategory::Rpc, rpc_span::prefix::command, "submit"); span.setAttribute(rpc_span::attr::command, "submit"); - span.setAttribute(rpc_span::attr::status, rpc_span::val::success); + span.setAttribute(rpc_span::attr::rpcStatus, rpc_span::val::success); // span ended automatically on scope exit @endcode @@ -83,7 +83,7 @@ TraceCategory::Rpc, rpc_span::prefix::rpc, "request"); if (span) { // expensive attribute computation only when active - span.setAttribute(rpc_span::attr::payloadSize, computeSize()); + span.setAttribute(rpc_span::attr::requestPayloadSize, computeSize()); } @endcode diff --git a/include/xrpl/telemetry/SpanNames.h b/include/xrpl/telemetry/SpanNames.h index 76f13c8851..3c8b6144f9 100644 --- a/include/xrpl/telemetry/SpanNames.h +++ b/include/xrpl/telemetry/SpanNames.h @@ -16,9 +16,12 @@ * concatenation support. boost::static_string is not constexpr. * StaticStr exists specifically for compile-time dot-join composition. * - * Naming conventions follow OpenTelemetry semantic conventions: - * - Attribute keys: "xrpl.." - * - Span prefixes: "[.]" + * Naming conventions (see spec 2026-05-13-span-attr-naming-design): + * - Per-span attribute keys: bare field name (span name carries the domain). + * - Collision qualifier: _ when bare name collides across + * domains or with OTel reserved `status` (e.g. rpc_status, grpc_status). + * - Resource attribute keys: xrpl.. (process-identity). + * - Span prefixes: [.]. */ #include @@ -98,7 +101,7 @@ inline constexpr auto link = makeStr("link"); namespace attr { inline constexpr auto networkId = join(join(seg::xrpl, seg::network), makeStr("id")); inline constexpr auto networkType = join(join(seg::xrpl, seg::network), makeStr("type")); -inline constexpr auto linkType = join(join(seg::xrpl, seg::link), makeStr("type")); +inline constexpr auto linkType = makeStr("link_type"); } // namespace attr // ===== Shared attribute values ============================================= diff --git a/src/xrpld/app/main/GrpcSpanNames.h b/src/xrpld/app/main/GrpcSpanNames.h index 869d5628aa..76166e86cb 100644 --- a/src/xrpld/app/main/GrpcSpanNames.h +++ b/src/xrpld/app/main/GrpcSpanNames.h @@ -11,7 +11,7 @@ * +-------------------------------------------------------+ * | grpc.request | * | CallData::process(coro) | - * | attrs: method, role, status | + * | attrs: method, grpc_role, grpc_status | * +-------------------------------------------------------+ * * Unlike the HTTP/WS RPC path, gRPC has a flat single-span structure @@ -38,14 +38,12 @@ inline constexpr auto request = makeStr("request"); // ===== Attribute keys ====================================================== namespace attr { -inline constexpr auto xrplGrpc = join(seg::xrpl, makeStr("grpc")); - -/// "xrpl.grpc.method" -inline constexpr auto method = join(xrplGrpc, makeStr("method")); -/// "xrpl.grpc.role" -inline constexpr auto role = join(xrplGrpc, makeStr("role")); -/// "xrpl.grpc.status" -inline constexpr auto status = join(xrplGrpc, makeStr("status")); +/// "method" — gRPC method name (e.g. GetLedger). +inline constexpr auto method = makeStr("method"); +/// "grpc_role" — Domain-qualified: collides with rpc_role. +inline constexpr auto grpcRole = makeStr("grpc_role"); +/// "grpc_status" — Domain-qualified: avoids OTel reserved span status. +inline constexpr auto grpcStatus = makeStr("grpc_status"); } // namespace attr // ===== Attribute values ==================================================== diff --git a/src/xrpld/rpc/detail/RPCHandler.cpp b/src/xrpld/rpc/detail/RPCHandler.cpp index dea2343f6c..c19eefec37 100644 --- a/src/xrpld/rpc/detail/RPCHandler.cpp +++ b/src/xrpld/rpc/detail/RPCHandler.cpp @@ -166,7 +166,7 @@ callMethod(JsonContext& context, Method method, std::string const& name, Object& span.setAttribute(rpc_span::attr::command, name.c_str()); span.setAttribute(rpc_span::attr::version, static_cast(context.apiVersion)); span.setAttribute( - rpc_span::attr::role, + rpc_span::attr::rpcRole, context.role == Role::ADMIN ? std::string_view(rpc_span::val::admin) : std::string_view(rpc_span::val::user)); @@ -185,7 +185,7 @@ callMethod(JsonContext& context, Method method, std::string const& name, Object& JLOG(context.j.debug()) << "RPC call " << name << " completed in " << ((end - start).count() / 1000000000.0) << "seconds"; perfLog.rpcFinish(name, curId); - span.setAttribute(rpc_span::attr::status, rpc_span::val::success); + span.setAttribute(rpc_span::attr::rpcStatus, rpc_span::val::success); return ret; } catch (std::exception& e) @@ -193,7 +193,7 @@ callMethod(JsonContext& context, Method method, std::string const& name, Object& perfLog.rpcError(name, curId); JLOG(context.j.info()) << "Caught throw: " << e.what(); span.recordException(e); - span.setAttribute(rpc_span::attr::status, rpc_span::val::error); + span.setAttribute(rpc_span::attr::rpcStatus, rpc_span::val::error); if (context.loadType == Resource::feeReferenceRPC) context.loadType = Resource::feeExceptionRPC; diff --git a/src/xrpld/rpc/detail/RpcSpanNames.h b/src/xrpld/rpc/detail/RpcSpanNames.h index 8e88f09717..c99c153f11 100644 --- a/src/xrpld/rpc/detail/RpcSpanNames.h +++ b/src/xrpld/rpc/detail/RpcSpanNames.h @@ -14,7 +14,7 @@ * auto span = SpanGuard::span( * TraceCategory::Rpc, rpc_span::prefix::command, "submit"); * span.setAttribute(rpc_span::attr::command, "submit"); - * span.setAttribute(rpc_span::attr::status, rpc_span::val::success); + * span.setAttribute(rpc_span::attr::rpcStatus, rpc_span::val::success); * @endcode * * Span hierarchy (automatic nesting via OTel thread-local context): @@ -32,7 +32,7 @@ * | | +---------------------------------------------+ | | * | | | rpc.command.{name} | | | * | | | RPC::callMethod() | | | - * | | | attrs: command, version, role, status | | | + * | | | attrs: command, version, rpc_role, rpc_status | | | * | | +---------------------------------------------+ | | * | +--------------------------------------------------+ | * +-------------------------------------------------------+ @@ -60,7 +60,7 @@ * | +--------------------------------------------------+ | * | | rpc.command.{name} | | * | | RPC::callMethod() | | - * | | attrs: command, version, role, status | | + * | | attrs: command, version, rpc_role, rpc_status | | * | +--------------------------------------------------+ | * +-------------------------------------------------------+ * @@ -88,7 +88,7 @@ * +-------------------------------------------------------+ * | grpc.request | * | CallData::process(coro) | - * | attrs: method, status | + * | attrs: method, grpc_status | * +-------------------------------------------------------+ * * Covered paths: @@ -134,18 +134,16 @@ inline constexpr auto process = makeStr("process"); // ===== Attribute keys ====================================================== namespace attr { -inline constexpr auto xrplRpc = join(seg::xrpl, seg::rpc); - -/// "xrpl.rpc.command" -inline constexpr auto command = join(xrplRpc, makeStr("command")); -/// "xrpl.rpc.version" -inline constexpr auto version = join(xrplRpc, makeStr("version")); -/// "xrpl.rpc.role" -inline constexpr auto role = join(xrplRpc, makeStr("role")); -/// "xrpl.rpc.status" -inline constexpr auto status = join(xrplRpc, makeStr("status")); -/// "xrpl.rpc.payload_size" -inline constexpr auto payloadSize = join(xrplRpc, makeStr("payload_size")); +/// "command" — RPC method name. +inline constexpr auto command = makeStr("command"); +/// "version" — api_version per request. +inline constexpr auto version = makeStr("version"); +/// "rpc_role" — admin|user. Domain-qualified: collides with grpc_role. +inline constexpr auto rpcRole = makeStr("rpc_role"); +/// "rpc_status" — success|error. Domain-qualified: avoids OTel reserved span status. +inline constexpr auto rpcStatus = makeStr("rpc_status"); +/// "request_payload_size" — bytes of inbound request payload. +inline constexpr auto requestPayloadSize = makeStr("request_payload_size"); } // namespace attr // ===== Attribute values ==================================================== diff --git a/src/xrpld/rpc/detail/ServerHandler.cpp b/src/xrpld/rpc/detail/ServerHandler.cpp index 85454e4a29..a181ec56cd 100644 --- a/src/xrpld/rpc/detail/ServerHandler.cpp +++ b/src/xrpld/rpc/detail/ServerHandler.cpp @@ -513,7 +513,7 @@ ServerHandler::processSession( JLOG(m_journal.error()) << "Exception while processing WS: " << ex.what() << "\n" << "Input JSON: " << Json::Compact{Json::Value{jv}}; span.recordException(ex); - span.setAttribute(rpc_span::attr::status, rpc_span::val::error); + span.setAttribute(rpc_span::attr::rpcStatus, rpc_span::val::error); // LCOV_EXCL_STOP } @@ -904,7 +904,7 @@ ServerHandler::processRequest( << "Internal error : " << ex.what() << " when processing request: " << Json::Compact{Json::Value{params}}; span.recordException(ex); - span.setAttribute(rpc_span::attr::status, rpc_span::val::error); + span.setAttribute(rpc_span::attr::rpcStatus, rpc_span::val::error); // LCOV_EXCL_STOP } From 497dd007d9ffb190968e517e06095779014bb2db Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Wed, 13 May 2026 15:57:36 +0100 Subject: [PATCH 3/5] =?UTF-8?q?refactor(telemetry):=20simplify=20attr=20na?= =?UTF-8?q?ming=20on=20phase-2=20=E2=80=94=20drop=20xrpl.pathfind.=20prefi?= =?UTF-8?q?x?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Drop xrpl.pathfind.* prefix from per-span attrs (source_account, dest_account, fast, search_level, num_complete_paths, num_paths, num_requests). - Keep xrpl.pathfind.ledger_index qualified (rule 5: distinct from xrpl.ledger.seq). - Remove per-span nodeAmendmentBlocked/nodeServerState calls from RPCHandler — promoted to resource-level attrs. - Mark node-health attrs in SpanNames.h as RESOURCE-ONLY with doc. Co-Authored-By: Claude Opus 4.6 (1M context) --- include/xrpl/telemetry/SpanNames.h | 8 ++++-- src/xrpld/rpc/detail/PathFindSpanNames.h | 36 ++++++++++++------------ src/xrpld/rpc/detail/RPCHandler.cpp | 2 -- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/xrpl/telemetry/SpanNames.h b/include/xrpl/telemetry/SpanNames.h index e5a9b125d6..685e88db6a 100644 --- a/include/xrpl/telemetry/SpanNames.h +++ b/include/xrpl/telemetry/SpanNames.h @@ -103,11 +103,13 @@ inline constexpr auto networkId = join(join(seg::xrpl, seg::network), makeStr("i inline constexpr auto networkType = join(join(seg::xrpl, seg::network), makeStr("type")); inline constexpr auto linkType = makeStr("link_type"); -/// Node health attributes (cross-cutting, used by RPC/consensus/tx spans). +/// Node health attributes — RESOURCE-ONLY (process identity, not per-span). +/// Set at Tracer init via resource::Resource::Create and refreshed on state +/// transitions. Do NOT use with span.setAttribute(). inline constexpr auto xrplNode = join(seg::xrpl, makeStr("node")); -/// "xrpl.node.amendment_blocked" +/// "xrpl.node.amendment_blocked" — resource attribute key. inline constexpr auto nodeAmendmentBlocked = join(xrplNode, makeStr("amendment_blocked")); -/// "xrpl.node.server_state" +/// "xrpl.node.server_state" — resource attribute key. inline constexpr auto nodeServerState = join(xrplNode, makeStr("server_state")); } // namespace attr diff --git a/src/xrpld/rpc/detail/PathFindSpanNames.h b/src/xrpld/rpc/detail/PathFindSpanNames.h index 40c9509cca..af61340b6f 100644 --- a/src/xrpld/rpc/detail/PathFindSpanNames.h +++ b/src/xrpld/rpc/detail/PathFindSpanNames.h @@ -63,24 +63,24 @@ inline constexpr auto rank = makeStr("rank"); // ===== Attribute keys ====================================================== namespace attr { -inline constexpr auto xrplPathfind = join(seg::xrpl, makeStr("pathfind")); - -/// "xrpl.pathfind.source_account" -inline constexpr auto sourceAccount = join(xrplPathfind, makeStr("source_account")); -/// "xrpl.pathfind.dest_account" -inline constexpr auto destAccount = join(xrplPathfind, makeStr("dest_account")); -/// "xrpl.pathfind.fast" -inline constexpr auto fast = join(xrplPathfind, makeStr("fast")); -/// "xrpl.pathfind.search_level" -inline constexpr auto searchLevel = join(xrplPathfind, makeStr("search_level")); -/// "xrpl.pathfind.num_complete_paths" -inline constexpr auto numCompletePaths = join(xrplPathfind, makeStr("num_complete_paths")); -/// "xrpl.pathfind.num_paths" -inline constexpr auto numPaths = join(xrplPathfind, makeStr("num_paths")); -/// "xrpl.pathfind.num_requests" -inline constexpr auto numRequests = join(xrplPathfind, makeStr("num_requests")); -/// "xrpl.pathfind.ledger_index" -inline constexpr auto ledgerIndex = join(xrplPathfind, makeStr("ledger_index")); +/// "source_account" — originating account for path search. +inline constexpr auto sourceAccount = makeStr("source_account"); +/// "dest_account" — destination account. +inline constexpr auto destAccount = makeStr("dest_account"); +/// "fast" — whether fast pathfinding mode enabled. +inline constexpr auto fast = makeStr("fast"); +/// "search_level" — depth of graph exploration. +inline constexpr auto searchLevel = makeStr("search_level"); +/// "num_complete_paths" — complete paths found. +inline constexpr auto numCompletePaths = makeStr("num_complete_paths"); +/// "num_paths" — total paths returned. +inline constexpr auto numPaths = makeStr("num_paths"); +/// "num_requests" — active path requests. +inline constexpr auto numRequests = makeStr("num_requests"); +/// "xrpl.pathfind.ledger_index" — kept qualified (rule 5): pathfind target +/// ledger is distinct from xrpl.ledger.seq. +inline constexpr auto ledgerIndex = + join(join(seg::xrpl, makeStr("pathfind")), makeStr("ledger_index")); } // namespace attr } // namespace xrpl::telemetry::pathfind_span diff --git a/src/xrpld/rpc/detail/RPCHandler.cpp b/src/xrpld/rpc/detail/RPCHandler.cpp index 45756b00aa..210e0e25fe 100644 --- a/src/xrpld/rpc/detail/RPCHandler.cpp +++ b/src/xrpld/rpc/detail/RPCHandler.cpp @@ -171,8 +171,6 @@ callMethod(JsonContext& context, Method method, std::string const& name, Object& rpc_span::attr::rpcRole, context.role == Role::ADMIN ? std::string_view(rpc_span::val::admin) : std::string_view(rpc_span::val::user)); - span.setAttribute(attr::nodeAmendmentBlocked, context.app.getOPs().isAmendmentBlocked()); - span.setAttribute(attr::nodeServerState, context.app.getOPs().strOperatingMode()); static std::atomic requestId{0}; auto& perfLog = context.app.getPerfLog(); From e339ba1f6b567e080529f64b2e2074e13cd5f2d0 Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Wed, 13 May 2026 16:01:00 +0100 Subject: [PATCH 4/5] =?UTF-8?q?refactor(telemetry):=20simplify=20tx/txq=20?= =?UTF-8?q?attr=20naming=20on=20phase-3=20=E2=80=94=20drop=20xrpl.?= =?UTF-8?q?.=20prefix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add canonical shared attrs to SpanNames.h: txHash (xrpl.tx.hash), peerId (xrpl.peer.id), ledgerSeq (xrpl.ledger.seq). - Drop xrpl.tx.* prefix: local, path, suppressed, peer_version. - Domain-qualify: status -> tx_status, txq status -> txq_status. - TxQ: tx_hash -> reuse canonical txHash, ledger_seq -> reuse canonical ledgerSeq; bare names for fee_level_paid, required_fee_level, etc. - Update call sites in PeerImp.cpp, NetworkOPs.cpp. Co-Authored-By: Claude Opus 4.6 (1M context) --- include/xrpl/telemetry/SpanNames.h | 6 ++++ src/xrpld/app/misc/NetworkOPs.cpp | 2 +- src/xrpld/app/misc/TxSpanNames.h | 31 +++++++---------- src/xrpld/app/misc/detail/TxQSpanNames.h | 44 +++++++++++------------- src/xrpld/overlay/detail/PeerImp.cpp | 6 ++-- 5 files changed, 44 insertions(+), 45 deletions(-) diff --git a/include/xrpl/telemetry/SpanNames.h b/include/xrpl/telemetry/SpanNames.h index 685e88db6a..78150d56ac 100644 --- a/include/xrpl/telemetry/SpanNames.h +++ b/include/xrpl/telemetry/SpanNames.h @@ -111,6 +111,12 @@ inline constexpr auto xrplNode = join(seg::xrpl, makeStr("node")); inline constexpr auto nodeAmendmentBlocked = join(xrplNode, makeStr("amendment_blocked")); /// "xrpl.node.server_state" — resource attribute key. inline constexpr auto nodeServerState = join(xrplNode, makeStr("server_state")); + +/// Canonical shared attrs (rule 5 — kept xrpl..* form). +/// Defined once here, aliased by domain-specific headers. +inline constexpr auto txHash = join(join(seg::xrpl, seg::tx), makeStr("hash")); +inline constexpr auto peerId = join(join(seg::xrpl, seg::peer), makeStr("id")); +inline constexpr auto ledgerSeq = join(join(seg::xrpl, seg::ledger), makeStr("seq")); } // namespace attr // ===== Shared attribute values ============================================= diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index ff7d24dd26..a956f3413f 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -1325,7 +1325,7 @@ NetworkOPsImp::processTransaction( { using namespace telemetry; auto span = std::make_shared(txProcessSpan(transaction->getID())); - span->setAttribute(tx_span::attr::hash, to_string(transaction->getID()).c_str()); + span->setAttribute(tx_span::attr::txHash, to_string(transaction->getID()).c_str()); span->setAttribute(tx_span::attr::local, bLocal); auto ev = m_job_queue.makeLoadEvent(jtTXN_PROC, "ProcessTXN"); diff --git a/src/xrpld/app/misc/TxSpanNames.h b/src/xrpld/app/misc/TxSpanNames.h index 091213959e..964246fcd6 100644 --- a/src/xrpld/app/misc/TxSpanNames.h +++ b/src/xrpld/app/misc/TxSpanNames.h @@ -41,25 +41,20 @@ inline constexpr auto process = join(prefix::tx, op::process); // ===== Attribute keys ====================================================== namespace attr { -inline constexpr auto xrplTx = join(seg::xrpl, seg::tx); +/// Canonical shared constants (defined in SpanNames.h). +using ::xrpl::telemetry::attr::peerId; +using ::xrpl::telemetry::attr::txHash; -/// "xrpl.tx.hash" -inline constexpr auto hash = join(xrplTx, makeStr("hash")); -/// "xrpl.tx.local" -inline constexpr auto local = join(xrplTx, makeStr("local")); -/// "xrpl.tx.path" -inline constexpr auto path = join(xrplTx, makeStr("path")); -/// "xrpl.tx.suppressed" -inline constexpr auto suppressed = join(xrplTx, makeStr("suppressed")); -/// "xrpl.tx.status" -inline constexpr auto status = join(xrplTx, makeStr("status")); - -inline constexpr auto xrplPeer = join(seg::xrpl, seg::peer); - -/// "xrpl.peer.id" -inline constexpr auto peerId = join(xrplPeer, makeStr("id")); -/// "xrpl.peer.version" -inline constexpr auto peerVersion = join(xrplPeer, makeStr("version")); +/// "local" — whether tx originated locally. +inline constexpr auto local = makeStr("local"); +/// "path" — sync or async processing path. +inline constexpr auto path = makeStr("path"); +/// "suppressed" — whether tx was suppressed as duplicate. +inline constexpr auto suppressed = makeStr("suppressed"); +/// "tx_status" — domain-qualified (collides with rpc_status, txq_status). +inline constexpr auto txStatus = makeStr("tx_status"); +/// "peer_version" — version of peer that sent the tx. +inline constexpr auto peerVersion = makeStr("peer_version"); } // namespace attr // ===== Attribute values ==================================================== diff --git a/src/xrpld/app/misc/detail/TxQSpanNames.h b/src/xrpld/app/misc/detail/TxQSpanNames.h index 4f18e82ae7..4268a8f5b4 100644 --- a/src/xrpld/app/misc/detail/TxQSpanNames.h +++ b/src/xrpld/app/misc/detail/TxQSpanNames.h @@ -71,30 +71,28 @@ inline constexpr auto cleanup = makeStr("cleanup"); // ===== Attribute keys ====================================================== namespace attr { -inline constexpr auto xrplTxq = join(seg::xrpl, makeStr("txq")); +/// Canonical shared constants (defined in SpanNames.h). +using ::xrpl::telemetry::attr::ledgerSeq; +using ::xrpl::telemetry::attr::txHash; -/// "xrpl.txq.tx_hash" -inline constexpr auto txHash = join(xrplTxq, makeStr("tx_hash")); -/// "xrpl.txq.status" -inline constexpr auto status = join(xrplTxq, makeStr("status")); -/// "xrpl.txq.fee_level_paid" -inline constexpr auto feeLevelPaid = join(xrplTxq, makeStr("fee_level_paid")); -/// "xrpl.txq.required_fee_level" -inline constexpr auto requiredFeeLevel = join(xrplTxq, makeStr("required_fee_level")); -/// "xrpl.txq.queue_size" -inline constexpr auto queueSize = join(xrplTxq, makeStr("queue_size")); -/// "xrpl.txq.ledger_changed" -inline constexpr auto ledgerChanged = join(xrplTxq, makeStr("ledger_changed")); -/// "xrpl.txq.ledger_seq" -inline constexpr auto ledgerSeq = join(xrplTxq, makeStr("ledger_seq")); -/// "xrpl.txq.expired_count" -inline constexpr auto expiredCount = join(xrplTxq, makeStr("expired_count")); -/// "xrpl.txq.ter_code" -inline constexpr auto terCode = join(xrplTxq, makeStr("ter_code")); -/// "xrpl.txq.retries_remaining" -inline constexpr auto retriesRemaining = join(xrplTxq, makeStr("retries_remaining")); -/// "xrpl.txq.num_cleared" -inline constexpr auto numCleared = join(xrplTxq, makeStr("num_cleared")); +/// "txq_status" — domain-qualified (collides with tx_status, rpc_status). +inline constexpr auto txqStatus = makeStr("txq_status"); +/// "fee_level_paid" — fee level paid by queued tx. +inline constexpr auto feeLevelPaid = makeStr("fee_level_paid"); +/// "required_fee_level" — minimum fee level for inclusion. +inline constexpr auto requiredFeeLevel = makeStr("required_fee_level"); +/// "queue_size" — current TxQ depth. +inline constexpr auto queueSize = makeStr("queue_size"); +/// "ledger_changed" — whether ledger changed since last attempt. +inline constexpr auto ledgerChanged = makeStr("ledger_changed"); +/// "expired_count" — number of expired entries cleared. +inline constexpr auto expiredCount = makeStr("expired_count"); +/// "ter_code" — transaction engine result code. +inline constexpr auto terCode = makeStr("ter_code"); +/// "retries_remaining" — retries left before discard. +inline constexpr auto retriesRemaining = makeStr("retries_remaining"); +/// "num_cleared" — entries cleared in batch. +inline constexpr auto numCleared = makeStr("num_cleared"); } // namespace attr // ===== Attribute values ==================================================== diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 1f19847cda..f281246b1c 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -1444,7 +1444,7 @@ PeerImp::handleTransaction( using namespace telemetry; auto span = std::make_shared(txReceiveSpan(txID, *m)); - span->setAttribute(tx_span::attr::hash, to_string(txID).c_str()); + span->setAttribute(tx_span::attr::txHash, to_string(txID).c_str()); span->setAttribute(tx_span::attr::peerId, static_cast(id_)); if (auto const version = getVersion(); !version.empty()) span->setAttribute(tx_span::attr::peerVersion, version.c_str()); @@ -1452,7 +1452,7 @@ PeerImp::handleTransaction( // on the span. The suppressed path overrides these when the // transaction has already been seen via HashRouter. span->setAttribute(tx_span::attr::suppressed, false); - span->setAttribute(tx_span::attr::status, "new"); + span->setAttribute(tx_span::attr::txStatus, "new"); // Charge strongly for attempting to relay a txn with tfInnerBatchTxn // LCOV_EXCL_START @@ -1490,7 +1490,7 @@ PeerImp::handleTransaction( // we have seen this transaction recently if (any(flags & HashRouterFlags::BAD)) { - span->setAttribute(tx_span::attr::status, tx_span::val::knownBad); + span->setAttribute(tx_span::attr::txStatus, tx_span::val::knownBad); fee_.update(Resource::feeUselessData, "known bad"); JLOG(p_journal_.debug()) << "Ignoring known bad tx " << txID; } From 46d1012ad433357a23d5eacc9365e8b7a80cf44b Mon Sep 17 00:00:00 2001 From: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Date: Wed, 13 May 2026 16:04:16 +0100 Subject: [PATCH 5/5] =?UTF-8?q?refactor(telemetry):=20simplify=20consensus?= =?UTF-8?q?=20attr=20naming=20on=20phase-4=20=E2=80=94=20drop=20xrpl.conse?= =?UTF-8?q?nsus.=20prefix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add canonical shared bare attrs to SpanNames.h: closeTime, closeTimeCorrect, closeResolutionMs (reused by ledger domain). - Keep qualified (rule 5): ledgerId, mode, round, roundId. - Domain-qualify collisions: state -> consensus_state, result -> consensus_result. - Reuse canonical ledgerSeq from phase-3. - Drop xrpl.consensus.* prefix from 20+ attrs (proposers, round_time_ms, converge_percent, avalanche_threshold, etc.). - Dispute attrs: bare names (dispute_our_vote, dispute_yays, etc.). - Update call sites in RCLConsensus.cpp, Consensus.h. Co-Authored-By: Claude Opus 4.6 (1M context) --- include/xrpl/telemetry/SpanNames.h | 5 + src/xrpld/app/consensus/RCLConsensus.cpp | 3 +- src/xrpld/consensus/Consensus.h | 2 +- src/xrpld/consensus/ConsensusSpanNames.h | 127 ++++++++--------------- 4 files changed, 49 insertions(+), 88 deletions(-) diff --git a/include/xrpl/telemetry/SpanNames.h b/include/xrpl/telemetry/SpanNames.h index 78150d56ac..88373b5f85 100644 --- a/include/xrpl/telemetry/SpanNames.h +++ b/include/xrpl/telemetry/SpanNames.h @@ -117,6 +117,11 @@ inline constexpr auto nodeServerState = join(xrplNode, makeStr("server_state")); inline constexpr auto txHash = join(join(seg::xrpl, seg::tx), makeStr("hash")); inline constexpr auto peerId = join(join(seg::xrpl, seg::peer), makeStr("id")); inline constexpr auto ledgerSeq = join(join(seg::xrpl, seg::ledger), makeStr("seq")); + +/// Shared close-time attrs — bare names, reused by consensus and ledger. +inline constexpr auto closeTime = makeStr("close_time"); +inline constexpr auto closeTimeCorrect = makeStr("close_time_correct"); +inline constexpr auto closeResolutionMs = makeStr("close_resolution_ms"); } // namespace attr // ===== Shared attribute values ============================================= diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index c11d944e50..985ee652bf 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -568,7 +568,8 @@ RCLConsensus::Adaptor::doAccept( static_cast( std::chrono::duration_cast(closeResolution).count())); doAcceptSpan.setAttribute( - telemetry::cons_span::attr::state, std::string(consensusFail ? "moved_on" : "finished")); + telemetry::cons_span::attr::consensusState, + std::string(consensusFail ? "moved_on" : "finished")); doAcceptSpan.setAttribute(telemetry::cons_span::attr::proposing, proposing); doAcceptSpan.setAttribute( telemetry::cons_span::attr::roundTimeMs, diff --git a/src/xrpld/consensus/Consensus.h b/src/xrpld/consensus/Consensus.h index f6bb1ecb22..3c1df2414d 100644 --- a/src/xrpld/consensus/Consensus.h +++ b/src/xrpld/consensus/Consensus.h @@ -1812,7 +1812,7 @@ Consensus::haveConsensus(std::unique_ptr const& clog { stateStr = "expired"; } - span.setAttribute(cons_span::attr::result, stateStr); + span.setAttribute(cons_span::attr::consensusResult, stateStr); CLOG(clog) << "Consensus has been reached. "; // NOLINTEND(bugprone-unchecked-optional-access) diff --git a/src/xrpld/consensus/ConsensusSpanNames.h b/src/xrpld/consensus/ConsensusSpanNames.h index b3112af1ec..d10a48c86e 100644 --- a/src/xrpld/consensus/ConsensusSpanNames.h +++ b/src/xrpld/consensus/ConsensusSpanNames.h @@ -124,96 +124,51 @@ inline constexpr auto phaseOpen = join(seg::consensus, op::phaseOpen); // ===== Attribute keys ======================================================== namespace attr { -inline constexpr auto xrplConsensus = join(seg::xrpl, seg::consensus); +/// Canonical shared constants (defined in SpanNames.h). +using ::xrpl::telemetry::attr::closeResolutionMs; +using ::xrpl::telemetry::attr::closeTime; +using ::xrpl::telemetry::attr::closeTimeCorrect; +using ::xrpl::telemetry::attr::ledgerSeq; -/// "xrpl.consensus.ledger_id" -inline constexpr auto ledgerId = join(xrplConsensus, makeStr("ledger_id")); -/// "xrpl.consensus.ledger.seq" -inline constexpr auto ledgerSeq = join(join(xrplConsensus, makeStr("ledger")), makeStr("seq")); -/// "xrpl.consensus.mode" -inline constexpr auto mode = join(xrplConsensus, makeStr("mode")); -/// "xrpl.consensus.round" -inline constexpr auto round = join(xrplConsensus, makeStr("round")); -/// "xrpl.consensus.proposers" -inline constexpr auto proposers = join(xrplConsensus, makeStr("proposers")); -/// "xrpl.consensus.round_time_ms" -inline constexpr auto roundTimeMs = join(xrplConsensus, makeStr("round_time_ms")); -/// "xrpl.consensus.proposing" -inline constexpr auto proposing = join(xrplConsensus, makeStr("proposing")); -/// "xrpl.consensus.state" -inline constexpr auto state = join(xrplConsensus, makeStr("state")); +/// Kept qualified (rule 5 — bare name ambiguous across domains). +inline constexpr auto ledgerId = join(join(seg::xrpl, seg::consensus), makeStr("ledger_id")); +inline constexpr auto mode = join(join(seg::xrpl, seg::consensus), makeStr("mode")); +inline constexpr auto round = join(join(seg::xrpl, seg::consensus), makeStr("round")); +inline constexpr auto roundId = join(join(seg::xrpl, seg::consensus), makeStr("round_id")); -// Close time attributes -/// "xrpl.consensus.close_time" -inline constexpr auto closeTime = join(xrplConsensus, makeStr("close_time")); -/// "xrpl.consensus.close_time_correct" -inline constexpr auto closeTimeCorrect = join(xrplConsensus, makeStr("close_time_correct")); -/// "xrpl.consensus.close_resolution_ms" -inline constexpr auto closeResolutionMs = join(xrplConsensus, makeStr("close_resolution_ms")); -/// "xrpl.consensus.parent_close_time" -inline constexpr auto parentCloseTime = join(xrplConsensus, makeStr("parent_close_time")); -/// "xrpl.consensus.close_time_self" -inline constexpr auto closeTimeSelf = join(xrplConsensus, makeStr("close_time_self")); -/// "xrpl.consensus.close_time_vote_bins" -inline constexpr auto closeTimeVoteBins = join(xrplConsensus, makeStr("close_time_vote_bins")); -/// "xrpl.consensus.resolution_direction" -inline constexpr auto resolutionDirection = join(xrplConsensus, makeStr("resolution_direction")); +/// Domain-owned bare attrs. +inline constexpr auto proposers = makeStr("proposers"); +inline constexpr auto roundTimeMs = makeStr("round_time_ms"); +inline constexpr auto proposing = makeStr("proposing"); +/// "consensus_state" — domain-qualified (collides with other domains' state). +inline constexpr auto consensusState = makeStr("consensus_state"); +inline constexpr auto parentCloseTime = makeStr("parent_close_time"); +inline constexpr auto closeTimeSelf = makeStr("close_time_self"); +inline constexpr auto closeTimeVoteBins = makeStr("close_time_vote_bins"); +inline constexpr auto resolutionDirection = makeStr("resolution_direction"); +inline constexpr auto convergePercent = makeStr("converge_percent"); +inline constexpr auto establishCount = makeStr("establish_count"); +inline constexpr auto avalancheThreshold = makeStr("avalanche_threshold"); +inline constexpr auto closeTimeThreshold = makeStr("close_time_threshold"); +inline constexpr auto haveCloseTimeConsensus = makeStr("have_close_time_consensus"); +inline constexpr auto agreeCount = makeStr("agree_count"); +inline constexpr auto disagreeCount = makeStr("disagree_count"); +inline constexpr auto thresholdPercent = makeStr("threshold_percent"); +/// "consensus_result" — domain-qualified (collides with generic result). +inline constexpr auto consensusResult = makeStr("consensus_result"); +inline constexpr auto quorum = makeStr("quorum"); +inline constexpr auto traceStrategy = makeStr("trace_strategy"); +inline constexpr auto modeOld = makeStr("mode_old"); +inline constexpr auto modeNew = makeStr("mode_new"); -// Establish/convergence attributes -/// "xrpl.consensus.converge_percent" -inline constexpr auto convergePercent = join(xrplConsensus, makeStr("converge_percent")); -/// "xrpl.consensus.establish_count" -inline constexpr auto establishCount = join(xrplConsensus, makeStr("establish_count")); -// Avalanche threshold attributes -/// "xrpl.consensus.avalanche_threshold" -inline constexpr auto avalancheThreshold = join(xrplConsensus, makeStr("avalanche_threshold")); -/// "xrpl.consensus.close_time_threshold" -inline constexpr auto closeTimeThreshold = join(xrplConsensus, makeStr("close_time_threshold")); -/// "xrpl.consensus.have_close_time_consensus" -inline constexpr auto haveCloseTimeConsensus = - join(xrplConsensus, makeStr("have_close_time_consensus")); - -// Consensus check attributes -/// "xrpl.consensus.agree_count" -inline constexpr auto agreeCount = join(xrplConsensus, makeStr("agree_count")); -/// "xrpl.consensus.disagree_count" -inline constexpr auto disagreeCount = join(xrplConsensus, makeStr("disagree_count")); -/// "xrpl.consensus.threshold_percent" -inline constexpr auto thresholdPercent = join(xrplConsensus, makeStr("threshold_percent")); -/// "xrpl.consensus.result" -inline constexpr auto result = join(xrplConsensus, makeStr("result")); -/// "xrpl.consensus.quorum" -inline constexpr auto quorum = join(xrplConsensus, makeStr("quorum")); - -// Trace strategy attribute -/// "xrpl.consensus.trace_strategy" -inline constexpr auto traceStrategy = join(xrplConsensus, makeStr("trace_strategy")); -/// "xrpl.consensus.round_id" -inline constexpr auto roundId = join(xrplConsensus, makeStr("round_id")); - -// Mode change attributes -/// "xrpl.consensus.mode.old" -inline constexpr auto modeOld = join(join(xrplConsensus, makeStr("mode")), makeStr("old")); -/// "xrpl.consensus.mode.new" -inline constexpr auto modeNew = join(join(xrplConsensus, makeStr("mode")), makeStr("new")); - -// Dispute event attributes -/// "xrpl.tx.id" +/// Transaction/dispute attrs used in consensus accept spans. inline constexpr auto txId = join(join(seg::xrpl, seg::tx), makeStr("id")); -/// "xrpl.dispute.our_vote" -inline constexpr auto disputeOurVote = - join(join(seg::xrpl, makeStr("dispute")), makeStr("our_vote")); -/// "xrpl.dispute.yays" -inline constexpr auto disputeYays = join(join(seg::xrpl, makeStr("dispute")), makeStr("yays")); -/// "xrpl.dispute.nays" -inline constexpr auto disputeNays = join(join(seg::xrpl, makeStr("dispute")), makeStr("nays")); - -/// "xrpl.consensus.tx_count" -inline constexpr auto txCount = join(xrplConsensus, makeStr("tx_count")); -/// "xrpl.consensus.disputes_count" -inline constexpr auto disputesCount = join(xrplConsensus, makeStr("disputes_count")); -/// "xrpl.consensus.trusted" -inline constexpr auto trusted = join(xrplConsensus, makeStr("trusted")); +inline constexpr auto disputeOurVote = makeStr("dispute_our_vote"); +inline constexpr auto disputeYays = makeStr("dispute_yays"); +inline constexpr auto disputeNays = makeStr("dispute_nays"); +inline constexpr auto txCount = makeStr("tx_count"); +inline constexpr auto disputesCount = makeStr("disputes_count"); +inline constexpr auto trusted = makeStr("trusted"); } // namespace attr // ===== Event names ===========================================================