mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 08:46:46 +00:00
Merge branch 'pratik/otel-phase7-native-metrics' into pratik/otel-phase8-log-correlation
This commit is contained in:
@@ -166,7 +166,7 @@ private:
|
||||
std::string m_name;
|
||||
GaugeImpl::value_type m_last_value{0};
|
||||
GaugeImpl::value_type m_value{0};
|
||||
bool m_dirty{false};
|
||||
bool m_dirty{true};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -583,6 +583,9 @@ StatsDEventImpl::do_notify(EventImpl::value_type const& value)
|
||||
StatsDGaugeImpl::StatsDGaugeImpl(std::string name, std::shared_ptr<StatsDCollectorImp> const& impl)
|
||||
: m_impl(impl), m_name(std::move(name))
|
||||
{
|
||||
// Start dirty so the initial value (0) is emitted on the first flush.
|
||||
// Without this, gauges whose value never changes from 0 would never
|
||||
// appear in downstream metric stores (e.g. Prometheus via StatsD).
|
||||
m_impl->add(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -568,7 +568,8 @@ RCLConsensus::Adaptor::doAccept(
|
||||
static_cast<int64_t>(
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(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,
|
||||
|
||||
@@ -82,7 +82,7 @@ buildLedgerImpl(
|
||||
built->header().seq < XRP_LEDGER_EARLIEST_FEES || built->read(keylet::fees()),
|
||||
"xrpl::buildLedgerImpl : valid ledger fees");
|
||||
built->setAccepted(closeTime, closeResolution, closeTimeCorrect);
|
||||
buildSpan.setAttribute(ledger_span::attr::seq, static_cast<int64_t>(built->header().seq));
|
||||
buildSpan.setAttribute(ledger_span::attr::ledgerSeq, static_cast<int64_t>(built->header().seq));
|
||||
buildSpan.setAttribute(
|
||||
ledger_span::attr::closeTime, static_cast<int64_t>(closeTime.time_since_epoch().count()));
|
||||
buildSpan.setAttribute(ledger_span::attr::closeTimeCorrect, closeTimeCorrect);
|
||||
|
||||
@@ -454,7 +454,7 @@ LedgerMaster::storeLedger(std::shared_ptr<Ledger const> ledger)
|
||||
{
|
||||
using namespace telemetry;
|
||||
auto span = SpanGuard::span(TraceCategory::Ledger, seg::ledger, ledger_span::op::store);
|
||||
span.setAttribute(ledger_span::attr::seq, static_cast<int64_t>(ledger->header().seq));
|
||||
span.setAttribute(ledger_span::attr::ledgerSeq, static_cast<int64_t>(ledger->header().seq));
|
||||
|
||||
bool const validated = ledger->header().validated;
|
||||
// Returns true if we already had the ledger
|
||||
@@ -974,7 +974,7 @@ LedgerMaster::checkAccept(std::shared_ptr<Ledger const> const& ledger)
|
||||
|
||||
using namespace telemetry;
|
||||
auto valSpan = SpanGuard::span(TraceCategory::Ledger, seg::ledger, ledger_span::op::validate);
|
||||
valSpan.setAttribute(ledger_span::attr::seq, static_cast<int64_t>(ledger->header().seq));
|
||||
valSpan.setAttribute(ledger_span::attr::ledgerSeq, static_cast<int64_t>(ledger->header().seq));
|
||||
valSpan.setAttribute(ledger_span::attr::validations, static_cast<int64_t>(tvc));
|
||||
|
||||
JLOG(m_journal.info()) << "Advancing accepted ledger to " << ledger->header().seq
|
||||
|
||||
@@ -29,22 +29,17 @@ inline constexpr auto apply = makeStr("apply");
|
||||
// ===== Attribute keys ========================================================
|
||||
|
||||
namespace attr {
|
||||
inline constexpr auto xrplLedger = join(seg::xrpl, seg::ledger);
|
||||
/// 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::ledgerHash;
|
||||
using ::xrpl::telemetry::attr::ledgerSeq;
|
||||
|
||||
/// "xrpl.ledger.seq"
|
||||
inline constexpr auto seq = join(xrplLedger, makeStr("seq"));
|
||||
/// "xrpl.ledger.close_time"
|
||||
inline constexpr auto closeTime = join(xrplLedger, makeStr("close_time"));
|
||||
/// "xrpl.ledger.close_time_correct"
|
||||
inline constexpr auto closeTimeCorrect = join(xrplLedger, makeStr("close_time_correct"));
|
||||
/// "xrpl.ledger.close_resolution_ms"
|
||||
inline constexpr auto closeResolutionMs = join(xrplLedger, makeStr("close_resolution_ms"));
|
||||
/// "xrpl.ledger.tx_count"
|
||||
inline constexpr auto txCount = join(xrplLedger, makeStr("tx_count"));
|
||||
/// "xrpl.ledger.tx_failed"
|
||||
inline constexpr auto txFailed = join(xrplLedger, makeStr("tx_failed"));
|
||||
/// "xrpl.ledger.validations"
|
||||
inline constexpr auto validations = join(xrplLedger, makeStr("validations"));
|
||||
/// Domain-owned bare attrs.
|
||||
inline constexpr auto txCount = makeStr("tx_count");
|
||||
inline constexpr auto txFailed = makeStr("tx_failed");
|
||||
inline constexpr auto validations = makeStr("validations");
|
||||
} // namespace attr
|
||||
|
||||
} // namespace xrpl::telemetry::ledger_span
|
||||
|
||||
@@ -149,6 +149,7 @@ private:
|
||||
beast::Journal m_journal;
|
||||
beast::io_latency_probe<std::chrono::steady_clock> m_probe;
|
||||
std::atomic<std::chrono::milliseconds> lastSample_;
|
||||
std::atomic<bool> firstSample_;
|
||||
|
||||
public:
|
||||
io_latency_sampler(
|
||||
@@ -156,7 +157,7 @@ private:
|
||||
beast::Journal journal,
|
||||
std::chrono::milliseconds interval,
|
||||
boost::asio::io_context& ios)
|
||||
: m_event(std::move(ev)), m_journal(journal), m_probe(interval, ios)
|
||||
: m_event(std::move(ev)), m_journal(journal), m_probe(interval, ios), firstSample_(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -175,7 +176,10 @@ private:
|
||||
|
||||
lastSample_ = lastSample;
|
||||
|
||||
if (lastSample >= 10ms)
|
||||
// Always emit the first sample so the metric is registered in
|
||||
// downstream stores (Prometheus via StatsD). After that, only
|
||||
// report latency >= 10 ms to avoid flooding with sub-ms values.
|
||||
if (firstSample_.exchange(false) || lastSample >= 10ms)
|
||||
m_event.notify(lastSample);
|
||||
if (lastSample >= 500ms)
|
||||
{
|
||||
|
||||
@@ -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 ====================================================
|
||||
|
||||
@@ -1325,7 +1325,7 @@ NetworkOPsImp::processTransaction(
|
||||
{
|
||||
using namespace telemetry;
|
||||
auto span = std::make_shared<SpanGuard>(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");
|
||||
|
||||
@@ -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 ====================================================
|
||||
|
||||
@@ -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 ====================================================
|
||||
|
||||
@@ -1812,7 +1812,7 @@ Consensus<Adaptor>::haveConsensus(std::unique_ptr<std::stringstream> 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)
|
||||
|
||||
@@ -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 ===========================================================
|
||||
|
||||
@@ -1447,10 +1447,15 @@ PeerImp::handleTransaction(
|
||||
|
||||
using namespace telemetry;
|
||||
auto span = std::make_shared<SpanGuard>(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<int64_t>(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::txStatus, "new");
|
||||
|
||||
// Charge strongly for attempting to relay a txn with tfInnerBatchTxn
|
||||
// LCOV_EXCL_START
|
||||
@@ -1488,7 +1493,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;
|
||||
}
|
||||
@@ -1870,7 +1875,7 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMProposeSet> const& m)
|
||||
{
|
||||
using namespace telemetry;
|
||||
auto span = SpanGuard::span(TraceCategory::Peer, seg::peer, peer_span::op::proposalReceive);
|
||||
span.setAttribute(peer_span::attr::id, static_cast<int64_t>(id_));
|
||||
span.setAttribute(peer_span::attr::peerId, static_cast<int64_t>(id_));
|
||||
|
||||
protocol::TMProposeSet const& set = *m;
|
||||
|
||||
@@ -2479,7 +2484,7 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMValidation> const& m)
|
||||
using namespace telemetry;
|
||||
auto valSpan =
|
||||
SpanGuard::span(TraceCategory::Peer, seg::peer, peer_span::op::validationReceive);
|
||||
valSpan.setAttribute(peer_span::attr::id, static_cast<int64_t>(id_));
|
||||
valSpan.setAttribute(peer_span::attr::peerId, static_cast<int64_t>(id_));
|
||||
|
||||
if (m->validation().size() < 50)
|
||||
{
|
||||
@@ -2503,8 +2508,7 @@ PeerImp::onMessage(std::shared_ptr<protocol::TMValidation> const& m)
|
||||
false);
|
||||
val->setSeen(closeTime);
|
||||
}
|
||||
valSpan.setAttribute(
|
||||
peer_span::attr::validationLedgerHash, to_string(val->getLedgerHash()).c_str());
|
||||
valSpan.setAttribute(peer_span::attr::ledgerHash, to_string(val->getLedgerHash()).c_str());
|
||||
valSpan.setAttribute(peer_span::attr::validationFull, val->isFull());
|
||||
|
||||
if (!isCurrent(
|
||||
|
||||
@@ -25,22 +25,14 @@ inline constexpr auto validationReceive = makeStr("validation.receive");
|
||||
// ===== Attribute keys ========================================================
|
||||
|
||||
namespace attr {
|
||||
inline constexpr auto xrplPeer = join(seg::xrpl, seg::peer);
|
||||
/// Canonical shared constants (defined in SpanNames.h).
|
||||
using ::xrpl::telemetry::attr::ledgerHash;
|
||||
using ::xrpl::telemetry::attr::peerId;
|
||||
|
||||
/// "xrpl.peer.id"
|
||||
inline constexpr auto id = join(xrplPeer, makeStr("id"));
|
||||
/// "xrpl.peer.proposal.trusted"
|
||||
inline constexpr auto proposalTrusted =
|
||||
join(join(xrplPeer, makeStr("proposal")), makeStr("trusted"));
|
||||
|
||||
/// "xrpl.peer.validation.ledger_hash"
|
||||
inline constexpr auto validationLedgerHash =
|
||||
join(join(xrplPeer, makeStr("validation")), makeStr("ledger_hash"));
|
||||
/// "xrpl.peer.validation.full"
|
||||
inline constexpr auto validationFull = join(join(xrplPeer, makeStr("validation")), makeStr("full"));
|
||||
/// "xrpl.peer.validation.trusted"
|
||||
inline constexpr auto validationTrusted =
|
||||
join(join(xrplPeer, makeStr("validation")), makeStr("trusted"));
|
||||
/// Domain-owned bare attrs.
|
||||
inline constexpr auto proposalTrusted = makeStr("proposal_trusted");
|
||||
inline constexpr auto validationFull = makeStr("validation_full");
|
||||
inline constexpr auto validationTrusted = makeStr("validation_trusted");
|
||||
} // namespace attr
|
||||
|
||||
} // namespace xrpl::telemetry::peer_span
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -168,11 +168,9 @@ 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<int64_t>(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));
|
||||
span.setAttribute(attr::nodeAmendmentBlocked, context.app.getOPs().isAmendmentBlocked());
|
||||
span.setAttribute(attr::nodeServerState, context.app.getOPs().strOperatingMode());
|
||||
|
||||
static std::atomic<std::uint64_t> requestId{0};
|
||||
auto& perfLog = context.app.getPerfLog();
|
||||
@@ -189,7 +187,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)
|
||||
@@ -197,7 +195,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;
|
||||
|
||||
@@ -14,8 +14,99 @@
|
||||
* 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):
|
||||
*
|
||||
* HTTP JSON-RPC path (single request):
|
||||
*
|
||||
* +-------------------------------------------------------+
|
||||
* | rpc.http_request |
|
||||
* | ServerHandler::processSession(Session) |
|
||||
* | |
|
||||
* | +--------------------------------------------------+ |
|
||||
* | | rpc.process | |
|
||||
* | | ServerHandler::processRequest() | |
|
||||
* | | | |
|
||||
* | | +---------------------------------------------+ | |
|
||||
* | | | rpc.command.{name} | | |
|
||||
* | | | RPC::callMethod() | | |
|
||||
* | | | attrs: command, version, rpc_role, rpc_status | | |
|
||||
* | | +---------------------------------------------+ | |
|
||||
* | +--------------------------------------------------+ |
|
||||
* +-------------------------------------------------------+
|
||||
*
|
||||
* HTTP batch path (multiple commands per request):
|
||||
*
|
||||
* +-------------------------------------------------------+
|
||||
* | rpc.http_request |
|
||||
* | |
|
||||
* | +--------------------------------------------------+ |
|
||||
* | | rpc.process | |
|
||||
* | | | |
|
||||
* | | +------------------+ +------------------+ | |
|
||||
* | | | rpc.command.{a} | | rpc.command.{b} | ... | |
|
||||
* | | +------------------+ +------------------+ | |
|
||||
* | +--------------------------------------------------+ |
|
||||
* +-------------------------------------------------------+
|
||||
*
|
||||
* WebSocket path:
|
||||
*
|
||||
* +-------------------------------------------------------+
|
||||
* | rpc.ws_message |
|
||||
* | ServerHandler::processSession(WSSession) |
|
||||
* | |
|
||||
* | +--------------------------------------------------+ |
|
||||
* | | rpc.command.{name} | |
|
||||
* | | RPC::callMethod() | |
|
||||
* | | attrs: command, version, rpc_role, rpc_status | |
|
||||
* | +--------------------------------------------------+ |
|
||||
* +-------------------------------------------------------+
|
||||
*
|
||||
* WebSocket error paths:
|
||||
*
|
||||
* +-------------------------------------------------------+
|
||||
* | rpc.ws_message (error: invalid_json) |
|
||||
* | ServerHandler::onWSMessage() — parse failure |
|
||||
* +-------------------------------------------------------+
|
||||
*
|
||||
* +-------------------------------------------------------+
|
||||
* | rpc.ws_upgrade |
|
||||
* | ServerHandler::onHandoff() — upgrade try/catch |
|
||||
* +-------------------------------------------------------+
|
||||
*
|
||||
* Command dispatch error path:
|
||||
*
|
||||
* +-------------------------------------------------------+
|
||||
* | rpc.command.{name} (error: too_busy/unknown/etc) |
|
||||
* | RPC::doCommand() — fillHandler() rejection |
|
||||
* +-------------------------------------------------------+
|
||||
*
|
||||
* gRPC path (see GrpcSpanNames.h for constants):
|
||||
*
|
||||
* +-------------------------------------------------------+
|
||||
* | grpc.request |
|
||||
* | CallData::process(coro) |
|
||||
* | attrs: method, grpc_status |
|
||||
* +-------------------------------------------------------+
|
||||
*
|
||||
* Covered paths:
|
||||
* - HTTP JSON-RPC (single and batch requests)
|
||||
* - WebSocket RPC commands
|
||||
* - WebSocket message parse errors (invalid JSON, oversized)
|
||||
* - WebSocket upgrade failures (protocol handshake errors)
|
||||
* - Admin CLI (connects via HTTP internally)
|
||||
* - Command dispatch rejections (unknown cmd, too busy, no perm)
|
||||
* - gRPC endpoints (GetLedger, GetLedgerData, GetLedgerDiff,
|
||||
* GetLedgerEntry)
|
||||
* - Command execution: timing, success/failure, exceptions
|
||||
* - Per-command attributes: name, API version, rpc_role, rpc_status
|
||||
*
|
||||
* Known gaps (not yet instrumented):
|
||||
* - Early validation errors in processRequest() before rpc.process
|
||||
* span (malformed JSON, auth failures, oversized requests)
|
||||
* - Subscription push notifications (server-initiated, not RPC)
|
||||
*/
|
||||
|
||||
#include <xrpl/telemetry/SpanNames.h>
|
||||
@@ -43,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 ====================================================
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user