diff --git a/.github/scripts/levelization/results/loops.txt b/.github/scripts/levelization/results/loops.txt index 16e62bb0a7..1f44b6159a 100644 --- a/.github/scripts/levelization/results/loops.txt +++ b/.github/scripts/levelization/results/loops.txt @@ -4,6 +4,9 @@ Loop: test.jtx test.toplevel Loop: test.jtx test.unit_test test.unit_test ~= test.jtx +Loop: xrpl.telemetry xrpld.consensus + xrpld.consensus ~= xrpl.telemetry + Loop: xrpl.telemetry xrpld.rpc xrpld.rpc > xrpl.telemetry diff --git a/.github/scripts/levelization/results/ordering.txt b/.github/scripts/levelization/results/ordering.txt index 39d06d61eb..102387de06 100644 --- a/.github/scripts/levelization/results/ordering.txt +++ b/.github/scripts/levelization/results/ordering.txt @@ -207,6 +207,8 @@ test.unit_test > xrpl.protocol tests.libxrpl > xrpl.basics tests.libxrpl > xrpl.config tests.libxrpl > xrpl.core +tests.libxrpl > xrpld.consensus +tests.libxrpl > xrpld.rpc tests.libxrpl > xrpl.json tests.libxrpl > xrpl.ledger tests.libxrpl > xrpl.net @@ -253,7 +255,6 @@ xrpl.shamap > xrpl.basics xrpl.shamap > xrpl.nodestore xrpl.shamap > xrpl.protocol xrpl.telemetry > xrpl.config -xrpl.telemetry > xrpld.consensus xrpl.tx > xrpl.basics xrpl.tx > xrpl.core xrpl.tx > xrpl.ledger @@ -280,7 +281,6 @@ xrpld.consensus > xrpl.basics xrpld.consensus > xrpl.json xrpld.consensus > xrpl.ledger xrpld.consensus > xrpl.protocol -xrpld.consensus > xrpl.telemetry xrpld.core > xrpl.basics xrpld.core > xrpl.config xrpld.core > xrpl.core @@ -332,4 +332,5 @@ xrpld.shamap > xrpld.core xrpld.shamap > xrpl.protocol xrpld.shamap > xrpl.shamap xrpld.telemetry > xrpl.basics +xrpld.telemetry > xrpld.consensus xrpld.telemetry > xrpl.telemetry diff --git a/conan.lock b/conan.lock index f83d3eccc6..ca5927801c 100644 --- a/conan.lock +++ b/conan.lock @@ -16,7 +16,7 @@ "nlohmann_json/3.11.3#45828be26eb619a2e04ca517bb7b828d%1701220705.259", "lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1765850143.914", "libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1765842973.492", - "libcurl/8.20.0#465ac276192c197ddc6a9f4494004278%1779353234.048", + "libcurl/8.20.0#c90b0c91a33d9a79b519c1c70bafc823%1780907438.587", "libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1765842973.03", "libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1778091117.848", "jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228", diff --git a/docker/telemetry/grafana/provisioning/datasources/tempo.yaml b/docker/telemetry/grafana/provisioning/datasources/tempo.yaml index 9d772ba96a..3e4065ccb9 100644 --- a/docker/telemetry/grafana/provisioning/datasources/tempo.yaml +++ b/docker/telemetry/grafana/provisioning/datasources/tempo.yaml @@ -126,17 +126,17 @@ datasources: type: dynamic # Phase 4: Consensus tracing filters - id: consensus-mode - tag: xrpl.consensus.mode + tag: consensus_mode operator: "=" scope: span type: static - id: consensus-round - tag: xrpl.consensus.round + tag: consensus_round operator: "=" scope: span type: dynamic - id: consensus-ledger-seq - tag: xrpl.ledger.seq + tag: ledger_seq operator: "=" scope: span type: static diff --git a/src/tests/libxrpl/telemetry/SpanGuardFactory.cpp b/src/tests/libxrpl/telemetry/SpanGuardFactory.cpp index aa935b2151..7f2df65485 100644 --- a/src/tests/libxrpl/telemetry/SpanGuardFactory.cpp +++ b/src/tests/libxrpl/telemetry/SpanGuardFactory.cpp @@ -1,12 +1,13 @@ +#include +#include + #include -#include #include #include #include #include -#include #include using namespace xrpl; @@ -30,8 +31,8 @@ TEST(SpanGuardFactory, category_span_returns_null_when_disabled) auto span = SpanGuard::span(TraceCategory::Rpc, "rpc", "test"); EXPECT_FALSE(span); - span.setAttribute("xrpl.rpc.command", "test"); - span.setAttribute("xrpl.rpc.status", "success"); + span.setAttribute(rpc_span::attr::command, "test"); + span.setAttribute(rpc_span::attr::rpcStatus, rpc_span::val::success); } TEST(SpanGuardFactory, child_span_null_when_no_parent) @@ -87,21 +88,22 @@ TEST(SpanGuardFactory, consensus_close_time_attributes) { // Verify the consensus attribute pattern compiles and // doesn't crash with null SpanGuard. + namespace cs = consensus::span; { auto span = telemetry::SpanGuard::span( - telemetry::TraceCategory::Consensus, telemetry::seg::consensus, "accept.apply"); - span.setAttribute("xrpl.consensus.ledger.seq", static_cast(42)); - span.setAttribute("xrpl.consensus.close_time", static_cast(780000000)); - span.setAttribute("xrpl.consensus.close_time_correct", true); - span.setAttribute("xrpl.consensus.close_resolution_ms", static_cast(30000)); - span.setAttribute("xrpl.consensus.state", std::string("finished")); - span.setAttribute("xrpl.consensus.proposing", true); - span.setAttribute("xrpl.consensus.round_time_ms", static_cast(3500)); + telemetry::TraceCategory::Consensus, telemetry::seg::consensus, cs::op::acceptApply); + span.setAttribute(cs::attr::ledgerSeq, static_cast(42)); + span.setAttribute(cs::attr::closeTime, static_cast(780000000)); + span.setAttribute(cs::attr::closeTimeCorrect, true); + span.setAttribute(cs::attr::closeResolutionMs, static_cast(30000)); + span.setAttribute(cs::attr::consensusState, cs::val::finished); + span.setAttribute(cs::attr::proposing, true); + span.setAttribute(cs::attr::roundTimeMs, static_cast(3500)); } { auto span = telemetry::SpanGuard::span( - telemetry::TraceCategory::Consensus, telemetry::seg::consensus, "accept.apply"); - span.setAttribute("xrpl.consensus.close_time_correct", false); - span.setAttribute("xrpl.consensus.state", std::string("moved_on")); + telemetry::TraceCategory::Consensus, telemetry::seg::consensus, cs::op::acceptApply); + span.setAttribute(cs::attr::closeTimeCorrect, false); + span.setAttribute(cs::attr::consensusState, cs::val::movedOn); } } diff --git a/src/tests/libxrpl/telemetry/TelemetryConfig.cpp b/src/tests/libxrpl/telemetry/TelemetryConfig.cpp index 137b30a62f..c8469bb44b 100644 --- a/src/tests/libxrpl/telemetry/TelemetryConfig.cpp +++ b/src/tests/libxrpl/telemetry/TelemetryConfig.cpp @@ -1,5 +1,5 @@ -#include #include +#include #include #include diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index db8a44675e..277b39938f 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -588,7 +588,8 @@ RCLConsensus::Adaptor::doAccept( static_cast( std::chrono::duration_cast(closeResolution).count())); doAcceptSpan.setAttribute( - cs::attr::consensusState, std::string(consensusFail ? "moved_on" : "finished")); + cs::attr::consensusState, + consensusFail ? std::string_view{cs::val::movedOn} : std::string_view{cs::val::finished}); doAcceptSpan.setAttribute(cs::attr::proposing, proposing); doAcceptSpan.setAttribute( cs::attr::roundTimeMs, static_cast(result.roundTime.read().count())); @@ -1284,7 +1285,7 @@ RCLConsensus::Adaptor::startRoundTracing(RCLCxLedger const& prevLgr) roundSpan_->setAttribute(cs::attr::previousProposers, static_cast(prevProposers_)); roundSpan_->setAttribute( cs::attr::previousRoundTimeMs, static_cast(prevRoundTime_.load().count())); - roundSpan_->setAttribute(cs::attr::consensusPhase, "open"); + roundSpan_->setAttribute(cs::attr::consensusPhase, cs::val::phaseOpen); roundSpan_->addEvent(cs::event::phaseOpen); diff --git a/src/xrpld/consensus/Consensus.h b/src/xrpld/consensus/Consensus.h index dbbcc8a0a9..ecd1b5fc60 100644 --- a/src/xrpld/consensus/Consensus.h +++ b/src/xrpld/consensus/Consensus.h @@ -744,7 +744,9 @@ Consensus::startRoundInternal( // after the new round span is in place. if (reason == StartRoundReason::Recovered) { - adaptor_.onPhaseEvent(telemetry::consensus::span::event::phaseOpen, "open"); + adaptor_.onPhaseEvent( + telemetry::consensus::span::event::phaseOpen, + telemetry::consensus::span::val::phaseOpen); } mode_.set(mode, adaptor_); now_ = now; @@ -994,7 +996,9 @@ Consensus::simulate( result_->proposers = prevProposers_ = currPeerPositions_.size(); prevRoundTime_ = result_->roundTime.read(); phase_ = ConsensusPhase::Accepted; - adaptor_.onPhaseEvent(telemetry::consensus::span::event::phaseAccepted, "accepted"); + adaptor_.onPhaseEvent( + telemetry::consensus::span::event::phaseAccepted, + telemetry::consensus::span::val::phaseAccepted); adaptor_.onForceAccept( *result_, previousLedger_, closeResolution_, rawCloseTimes_, mode_.get(), getJson(true)); // NOLINTEND(bugprone-unchecked-optional-access) @@ -1474,7 +1478,9 @@ Consensus::phaseEstablish(std::unique_ptr const& clo } } phase_ = ConsensusPhase::Accepted; - adaptor_.onPhaseEvent(telemetry::consensus::span::event::phaseAccepted, "accepted"); + adaptor_.onPhaseEvent( + telemetry::consensus::span::event::phaseAccepted, + telemetry::consensus::span::val::phaseAccepted); JLOG(j_.debug()) << "transitioned to ConsensusPhase::Accepted"; adaptor_.onAccept( *result_, @@ -1508,7 +1514,9 @@ Consensus::closeLedger(std::unique_ptr const& clog) } openSpan_.reset(); phase_ = ConsensusPhase::Establish; - adaptor_.onPhaseEvent(telemetry::consensus::span::event::phaseEstablish, "establish"); + adaptor_.onPhaseEvent( + telemetry::consensus::span::event::phaseEstablish, + telemetry::consensus::span::val::phaseEstablish); JLOG(j_.debug()) << "transitioned to ConsensusPhase::Establish"; rawCloseTimes_.self = now_; peerUnchangedCounter_ = 0; @@ -1638,7 +1646,9 @@ Consensus::updateOurPositions(std::unique_ptr const& span.addEvent( consensus::span::event::disputeResolve, {{consensus::span::attr::txId, to_string(txId)}, - {consensus::span::attr::disputeOurVote, dispute.getOurVote() ? "yes" : "no"}, + {consensus::span::attr::disputeOurVote, + dispute.getOurVote() ? std::string_view{consensus::span::val::yes} + : std::string_view{consensus::span::val::no}}, {consensus::span::attr::disputeYays, yaysStr}, {consensus::span::attr::disputeNays, naysStr}}); } @@ -1831,6 +1841,38 @@ Consensus::haveConsensus(std::unique_ptr const& clog j_, clog); + // Set span attributes before the early-return branches below so the + // consensus.check span carries diagnostic data even when consensus is + // not reached (the No / Expired paths return early). + span.setAttribute(consensus::span::attr::agreeCount, static_cast(agree)); + span.setAttribute(consensus::span::attr::disagreeCount, static_cast(disagree)); + span.setAttribute( + consensus::span::attr::convergePercent, static_cast(convergePercent_)); + span.setAttribute(consensus::span::attr::haveCloseTimeConsensus, haveCloseTimeConsensus_); + span.setAttribute( + consensus::span::attr::thresholdPercent, + static_cast(adaptor_.parms().avCtConsensusPct)); + span.setAttribute( + consensus::span::attr::proposersFinished, static_cast(currentFinished)); + span.setAttribute(consensus::span::attr::consensusStalled, stalled); + span.setAttribute( + consensus::span::attr::establishCounter, static_cast(establishCounter_)); + + std::string_view stateStr = consensus::span::val::no; + if (result_->state == ConsensusState::Yes) + { + stateStr = consensus::span::val::yes; + } + else if (result_->state == ConsensusState::MovedOn) + { + stateStr = consensus::span::val::movedOn; + } + else if (result_->state == ConsensusState::Expired) + { + stateStr = consensus::span::val::expired; + } + span.setAttribute(consensus::span::attr::consensusResult, stateStr); + if (result_->state == ConsensusState::No) { CLOG(clog) << "No consensus. "; @@ -1872,35 +1914,6 @@ Consensus::haveConsensus(std::unique_ptr const& clog CLOG(clog) << "Unable to reach consensus " << json::Compact{getJson(true)} << ". "; } - span.setAttribute(consensus::span::attr::agreeCount, static_cast(agree)); - span.setAttribute(consensus::span::attr::disagreeCount, static_cast(disagree)); - span.setAttribute( - consensus::span::attr::convergePercent, static_cast(convergePercent_)); - span.setAttribute(consensus::span::attr::haveCloseTimeConsensus, haveCloseTimeConsensus_); - span.setAttribute( - consensus::span::attr::thresholdPercent, - static_cast(adaptor_.parms().avCtConsensusPct)); - span.setAttribute( - consensus::span::attr::proposersFinished, static_cast(currentFinished)); - span.setAttribute(consensus::span::attr::consensusStalled, stalled); - span.setAttribute( - consensus::span::attr::establishCounter, static_cast(establishCounter_)); - - char const* stateStr = "no"; - if (result_->state == ConsensusState::Yes) - { - stateStr = "yes"; - } - else if (result_->state == ConsensusState::MovedOn) - { - stateStr = "moved_on"; - } - else if (result_->state == ConsensusState::Expired) - { - stateStr = "expired"; - } - span.setAttribute(consensus::span::attr::consensusResult, stateStr); - CLOG(clog) << "Consensus has been reached. "; // NOLINTEND(bugprone-unchecked-optional-access) return true; diff --git a/src/xrpld/consensus/ConsensusSpanNames.h b/src/xrpld/consensus/ConsensusSpanNames.h index e9b08b8439..7aa362adb1 100644 --- a/src/xrpld/consensus/ConsensusSpanNames.h +++ b/src/xrpld/consensus/ConsensusSpanNames.h @@ -238,6 +238,10 @@ inline constexpr auto expired = makeStr("expired"); inline constexpr auto increased = makeStr("increased"); inline constexpr auto decreased = makeStr("decreased"); inline constexpr auto unchanged = makeStr("unchanged"); +// consensus_phase attribute values (the phase the round is entering). +inline constexpr auto phaseOpen = makeStr("open"); +inline constexpr auto phaseEstablish = makeStr("establish"); +inline constexpr auto phaseAccepted = makeStr("accepted"); } // namespace val } // namespace xrpl::telemetry::consensus::span diff --git a/src/xrpld/telemetry/ConsensusReceiveTracing.h b/src/xrpld/telemetry/ConsensusReceiveTracing.h index 63bc34b243..3c7ea42ca6 100644 --- a/src/xrpld/telemetry/ConsensusReceiveTracing.h +++ b/src/xrpld/telemetry/ConsensusReceiveTracing.h @@ -31,25 +31,19 @@ * span.setAttribute(...); * @endcode * - * @note These span names use inline string_view literals. When - * ConsensusSpanNames.h (from Phase 4) is available, callers should - * migrate to using the constexpr constants defined there. + * @note Span names come from the canonical constants in + * ConsensusSpanNames.h (consensus::span::proposalReceive / + * validationReceive) so they stay in sync with the rest of Phase 4. */ +#include + #include #include #include namespace xrpl::telemetry { -// Inline span name constants for consensus receive spans. -// Phase 4 will provide these via ConsensusSpanNames.h; these are -// temporary definitions for the propagation infrastructure. -namespace detail { -inline constexpr std::string_view proposalReceiveName = "consensus.proposal.receive"; -inline constexpr std::string_view validationReceiveName = "consensus.validation.receive"; -} // namespace detail - /** Create a "consensus.proposal.receive" span for an incoming proposal. * * If the message carries a TraceContext with a valid span_id, the @@ -75,7 +69,7 @@ proposalReceiveSpan([[maybe_unused]] protocol::TMProposeSet const& msg) // trace_id so the receiving span shares the same trace. return SpanGuard::hashSpan( TraceCategory::Consensus, - detail::proposalReceiveName, + consensus::span::proposalReceive, reinterpret_cast(tc.trace_id().data()), tc.trace_id().size(), reinterpret_cast(tc.span_id().data()), @@ -86,7 +80,8 @@ proposalReceiveSpan([[maybe_unused]] protocol::TMProposeSet const& msg) } #endif // No propagated context — create a standalone span. - return SpanGuard::span(TraceCategory::Consensus, "consensus", "proposal.receive"); + return SpanGuard::span( + TraceCategory::Consensus, seg::consensus, consensus::span::op::proposalReceive); } /** Create a "consensus.validation.receive" span for an incoming validation. @@ -111,7 +106,7 @@ validationReceiveSpan([[maybe_unused]] protocol::TMValidation const& msg) { return SpanGuard::hashSpan( TraceCategory::Consensus, - detail::validationReceiveName, + consensus::span::validationReceive, reinterpret_cast(tc.trace_id().data()), tc.trace_id().size(), reinterpret_cast(tc.span_id().data()), @@ -122,7 +117,8 @@ validationReceiveSpan([[maybe_unused]] protocol::TMValidation const& msg) } #endif // No propagated context — create a standalone span. - return SpanGuard::span(TraceCategory::Consensus, "consensus", "validation.receive"); + return SpanGuard::span( + TraceCategory::Consensus, seg::consensus, consensus::span::op::validationReceive); } } // namespace xrpl::telemetry