mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 08:46:46 +00:00
Merge branch 'pratik/otel-phase5-docs-deployment' into pratik/otel-phase6-statsd
This commit is contained in:
10
docs/build/telemetry.md
vendored
10
docs/build/telemetry.md
vendored
@@ -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
|
||||
|
||||
|
||||
@@ -64,71 +64,71 @@ All spans instrumented in xrpld, grouped by subsystem:
|
||||
|
||||
### RPC Spans (Phase 2)
|
||||
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| -------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
|
||||
| `rpc.request` | ServerHandler.cpp:271 | — | Top-level HTTP RPC request |
|
||||
| `rpc.process` | ServerHandler.cpp:573 | — | RPC processing (child of rpc.request) |
|
||||
| `rpc.ws_message` | ServerHandler.cpp:384 | — | WebSocket RPC message |
|
||||
| `rpc.command.<name>` | RPCHandler.cpp:161 | `xrpl.rpc.command`, `xrpl.rpc.version`, `xrpl.rpc.role`, `xrpl.rpc.status`, `xrpl.rpc.duration_ms`, `xrpl.rpc.error_message` | Per-command span (e.g., `rpc.command.server_info`) |
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| -------------------- | --------------------- | ------------------------------------------------------------------------------ | -------------------------------------------------- |
|
||||
| `rpc.request` | ServerHandler.cpp:271 | — | Top-level HTTP RPC request |
|
||||
| `rpc.process` | ServerHandler.cpp:573 | — | RPC processing (child of rpc.request) |
|
||||
| `rpc.ws_message` | ServerHandler.cpp:384 | — | WebSocket RPC message |
|
||||
| `rpc.command.<name>` | RPCHandler.cpp:161 | `command`, `version`, `rpc_role`, `rpc_status`, `duration_ms`, `error_message` | Per-command span (e.g., `rpc.command.server_info`) |
|
||||
|
||||
### Transaction Spans (Phase 3)
|
||||
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ------------ | ------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------- |
|
||||
| `tx.process` | NetworkOPs.cpp:1227 | `xrpl.tx.hash`, `xrpl.tx.local`, `xrpl.tx.path` | Transaction submission and processing |
|
||||
| `tx.receive` | PeerImp.cpp:1273 | `xrpl.peer.id`, `xrpl.tx.hash`, `xrpl.peer.version`, `xrpl.tx.suppressed`, `xrpl.tx.status` | Transaction received from peer relay |
|
||||
| `tx.apply` | BuildLedger.cpp:88 | `xrpl.ledger.seq`, `xrpl.ledger.tx_count`, `xrpl.ledger.tx_failed` | Transaction set applied per ledger |
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ------------ | ------------------- | ------------------------------------------------------------------------- | ------------------------------------- |
|
||||
| `tx.process` | NetworkOPs.cpp:1227 | `xrpl.tx.hash`, `local`, `path` | Transaction submission and processing |
|
||||
| `tx.receive` | PeerImp.cpp:1273 | `xrpl.peer.id`, `xrpl.tx.hash`, `peer_version`, `suppressed`, `tx_status` | Transaction received from peer relay |
|
||||
| `tx.apply` | BuildLedger.cpp:88 | `xrpl.ledger.seq`, `tx_count`, `tx_failed` | Transaction set applied per ledger |
|
||||
|
||||
### Transaction Queue Spans (Phase 3)
|
||||
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ------------------ | ----------- | --------------------------------------------------------------------- | -------------------------------------------------- |
|
||||
| `txq.enqueue` | TxQ.cpp | `xrpl.txq.tx_hash` | Transaction enqueue decision (child of tx.process) |
|
||||
| `txq.apply_direct` | TxQ.cpp | -- | Direct apply attempt (bypassing queue) |
|
||||
| `txq.batch_clear` | TxQ.cpp | -- | Batch clear of queued transactions for an account |
|
||||
| `txq.accept` | TxQ.cpp | `xrpl.txq.queue_size` | Ledger-close accept loop over queued transactions |
|
||||
| `txq.accept_tx` | TxQ.cpp | `xrpl.txq.tx_hash`, `xrpl.txq.retries_remaining`, `xrpl.txq.ter_code` | Per-transaction apply during accept |
|
||||
| `txq.cleanup` | TxQ.cpp | `xrpl.txq.ledger_seq` | Post-close cleanup of expired queue entries |
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ------------------ | ----------- | ----------------------------------------------- | -------------------------------------------------- |
|
||||
| `txq.enqueue` | TxQ.cpp | `xrpl.tx.hash` | Transaction enqueue decision (child of tx.process) |
|
||||
| `txq.apply_direct` | TxQ.cpp | -- | Direct apply attempt (bypassing queue) |
|
||||
| `txq.batch_clear` | TxQ.cpp | -- | Batch clear of queued transactions for an account |
|
||||
| `txq.accept` | TxQ.cpp | `queue_size` | Ledger-close accept loop over queued transactions |
|
||||
| `txq.accept_tx` | TxQ.cpp | `xrpl.tx.hash`, `retries_remaining`, `ter_code` | Per-transaction apply during accept |
|
||||
| `txq.cleanup` | TxQ.cpp | `xrpl.ledger.seq` | Post-close cleanup of expired queue entries |
|
||||
|
||||
### Consensus Spans (Phase 4)
|
||||
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `consensus.round` | RCLConsensus.cpp | `xrpl.consensus.ledger_id`, `xrpl.consensus.ledger.seq`, `xrpl.consensus.mode`, `xrpl.consensus.trace_strategy`, `xrpl.consensus.round_id` | Root span for a consensus round (deterministic or random trace ID) |
|
||||
| `consensus.phase.open` | Consensus.h | -- | Open phase duration (child of round) |
|
||||
| `consensus.proposal.send` | RCLConsensus.cpp | `xrpl.consensus.round` | Consensus proposal broadcast |
|
||||
| `consensus.ledger_close` | RCLConsensus.cpp | `xrpl.consensus.ledger.seq`, `xrpl.consensus.mode` | Ledger close event |
|
||||
| `consensus.establish` | Consensus.h | `xrpl.consensus.converge_percent`, `xrpl.consensus.establish_count`, `xrpl.consensus.proposers` | Establish phase duration (child of round) |
|
||||
| `consensus.update_positions` | Consensus.h | `xrpl.consensus.converge_percent`, `xrpl.consensus.proposers`, `xrpl.consensus.disputes_count` | Position update and dispute resolution (see Events below) |
|
||||
| `consensus.check` | Consensus.h | `xrpl.consensus.agree_count`, `xrpl.consensus.disagree_count`, `xrpl.consensus.converge_percent`, `xrpl.consensus.have_close_time_consensus`, `xrpl.consensus.threshold_percent`, `xrpl.consensus.result` | Consensus threshold check |
|
||||
| `consensus.accept` | RCLConsensus.cpp | `xrpl.consensus.proposers`, `xrpl.consensus.round_time_ms`, `xrpl.consensus.quorum` | Ledger accepted by consensus |
|
||||
| `consensus.accept.apply` | RCLConsensus.cpp | `xrpl.consensus.ledger.seq`, `xrpl.consensus.close_time`, `xrpl.consensus.close_time_correct`, `xrpl.consensus.close_resolution_ms`, `xrpl.consensus.state`, `xrpl.consensus.proposing`, `xrpl.consensus.round_time_ms`, `xrpl.consensus.parent_close_time`, `xrpl.consensus.close_time_self`, `xrpl.consensus.close_time_vote_bins`, `xrpl.consensus.resolution_direction`, `xrpl.consensus.tx_count` | Ledger application with close time details (see Events below) |
|
||||
| `consensus.validation.send` | RCLConsensus.cpp | `xrpl.consensus.ledger.seq`, `xrpl.consensus.proposing` | Validation sent after accept (follows-from link) |
|
||||
| `consensus.mode_change` | RCLConsensus.cpp | `xrpl.consensus.mode.old`, `xrpl.consensus.mode.new` | Consensus mode transition |
|
||||
| `consensus.proposal.receive` | PeerImp.cpp | `xrpl.consensus.trusted`, `xrpl.consensus.round` | Proposal received from peer (extracts parent context from TraceContext when present; falls back to standalone span for older peers) |
|
||||
| `consensus.validation.receive` | PeerImp.cpp | `xrpl.consensus.trusted`, `xrpl.consensus.ledger.seq` | Validation received from peer (extracts parent context from TraceContext when present; falls back to standalone span for older peers) |
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ------------------------------ | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `consensus.round` | RCLConsensus.cpp | `xrpl.consensus.ledger_id`, `xrpl.ledger.seq`, `xrpl.consensus.mode`, `trace_strategy`, `xrpl.consensus.round_id` | Root span for a consensus round (deterministic or random trace ID) |
|
||||
| `consensus.phase.open` | Consensus.h | -- | Open phase duration (child of round) |
|
||||
| `consensus.proposal.send` | RCLConsensus.cpp | `xrpl.consensus.round` | Consensus proposal broadcast |
|
||||
| `consensus.ledger_close` | RCLConsensus.cpp | `xrpl.ledger.seq`, `xrpl.consensus.mode` | Ledger close event |
|
||||
| `consensus.establish` | Consensus.h | `converge_percent`, `establish_count`, `proposers` | Establish phase duration (child of round) |
|
||||
| `consensus.update_positions` | Consensus.h | `converge_percent`, `proposers`, `disputes_count` | Position update and dispute resolution (see Events below) |
|
||||
| `consensus.check` | Consensus.h | `agree_count`, `disagree_count`, `converge_percent`, `have_close_time_consensus`, `threshold_percent`, `consensus_result` | Consensus threshold check |
|
||||
| `consensus.accept` | RCLConsensus.cpp | `proposers`, `round_time_ms`, `quorum` | Ledger accepted by consensus |
|
||||
| `consensus.accept.apply` | RCLConsensus.cpp | `xrpl.ledger.seq`, `close_time`, `close_time_correct`, `close_resolution_ms`, `consensus_state`, `proposing`, `round_time_ms`, `parent_close_time`, `close_time_self`, `close_time_vote_bins`, `resolution_direction`, `tx_count` | Ledger application with close time details (see Events below) |
|
||||
| `consensus.validation.send` | RCLConsensus.cpp | `xrpl.ledger.seq`, `proposing` | Validation sent after accept (follows-from link) |
|
||||
| `consensus.mode_change` | RCLConsensus.cpp | `mode_old`, `mode_new` | Consensus mode transition |
|
||||
| `consensus.proposal.receive` | PeerImp.cpp | `trusted`, `xrpl.consensus.round` | Proposal received from peer (extracts parent context from TraceContext when present; falls back to standalone span for older peers) |
|
||||
| `consensus.validation.receive` | PeerImp.cpp | `trusted`, `xrpl.ledger.seq` | Validation received from peer (extracts parent context from TraceContext when present; falls back to standalone span for older peers) |
|
||||
|
||||
#### Consensus Span Events
|
||||
|
||||
| Parent Span | Event Name | Event Attributes | Description |
|
||||
| ---------------------------- | ----------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
||||
| `consensus.update_positions` | `dispute.resolve` | `xrpl.tx.id`, `xrpl.dispute.our_vote`, `xrpl.dispute.yays`, `xrpl.dispute.nays` | Emitted per dispute when votes are tallied |
|
||||
| `consensus.accept.apply` | `tx.included` | `xrpl.tx.id` | Emitted per transaction included in the accepted ledger |
|
||||
| Parent Span | Event Name | Event Attributes | Description |
|
||||
| ---------------------------- | ----------------- | ---------------------------------------------------------------- | ------------------------------------------------------- |
|
||||
| `consensus.update_positions` | `dispute.resolve` | `xrpl.tx.id`, `dispute_our_vote`, `dispute_yays`, `dispute_nays` | Emitted per dispute when votes are tallied |
|
||||
| `consensus.accept.apply` | `tx.included` | `xrpl.tx.id` | Emitted per transaction included in the accepted ledger |
|
||||
|
||||
#### Close Time Queries (Tempo TraceQL)
|
||||
|
||||
```
|
||||
# Find rounds where validators disagreed on close time
|
||||
{name="consensus.accept.apply"} | xrpl.consensus.close_time_correct = false
|
||||
{name="consensus.accept.apply"} | close_time_correct = false
|
||||
|
||||
# Find consensus failures (moved_on)
|
||||
{name="consensus.accept.apply"} | xrpl.consensus.state = "moved_on"
|
||||
{name="consensus.accept.apply"} | consensus_state = "moved_on"
|
||||
|
||||
# Find slow ledger applications (>5s)
|
||||
{name="consensus.accept.apply"} | duration > 5s
|
||||
|
||||
# Find specific ledger's consensus details
|
||||
{name="consensus.accept.apply"} | xrpl.consensus.ledger.seq = 92345678
|
||||
{name="consensus.accept.apply"} | xrpl.ledger.seq = 92345678
|
||||
|
||||
# Find all spans in a consensus round (deterministic trace strategy)
|
||||
{name="consensus.round"} | xrpl.consensus.round_id = "<round_id>"
|
||||
@@ -139,18 +139,18 @@ All spans instrumented in xrpld, grouped by subsystem:
|
||||
|
||||
### Ledger Spans (Phase 5)
|
||||
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ----------------- | -------------------- | ------------------------------------------------------------------ | ----------------------------- |
|
||||
| `ledger.build` | BuildLedger.cpp:31 | `xrpl.ledger.seq`, `xrpl.ledger.tx_count`, `xrpl.ledger.tx_failed` | Ledger build during consensus |
|
||||
| `ledger.validate` | LedgerMaster.cpp:915 | `xrpl.ledger.seq`, `xrpl.ledger.validations` | Ledger promoted to validated |
|
||||
| `ledger.store` | LedgerMaster.cpp:409 | `xrpl.ledger.seq` | Ledger stored in history |
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ----------------- | -------------------- | ------------------------------------------ | ----------------------------- |
|
||||
| `ledger.build` | BuildLedger.cpp:31 | `xrpl.ledger.seq`, `tx_count`, `tx_failed` | Ledger build during consensus |
|
||||
| `ledger.validate` | LedgerMaster.cpp:915 | `xrpl.ledger.seq`, `validations` | Ledger promoted to validated |
|
||||
| `ledger.store` | LedgerMaster.cpp:409 | `xrpl.ledger.seq` | Ledger stored in history |
|
||||
|
||||
### Peer Spans (Phase 5)
|
||||
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ------------------------- | ---------------- | ---------------------------------------------- | ----------------------------- |
|
||||
| `peer.proposal.receive` | PeerImp.cpp:1667 | `xrpl.peer.id`, `xrpl.peer.proposal.trusted` | Proposal received from peer |
|
||||
| `peer.validation.receive` | PeerImp.cpp:2264 | `xrpl.peer.id`, `xrpl.peer.validation.trusted` | Validation received from peer |
|
||||
| Span Name | Source File | Attributes | Description |
|
||||
| ------------------------- | ---------------- | ------------------------------------ | ----------------------------- |
|
||||
| `peer.proposal.receive` | PeerImp.cpp:1667 | `xrpl.peer.id`, `proposal_trusted` | Proposal received from peer |
|
||||
| `peer.validation.receive` | PeerImp.cpp:2264 | `xrpl.peer.id`, `validation_trusted` | Validation received from peer |
|
||||
|
||||
## Cross-Node Trace Propagation
|
||||
|
||||
@@ -259,14 +259,14 @@ Every metric carries these standard labels:
|
||||
|
||||
Additionally, span attributes configured as dimensions in the collector become metric labels (dots → underscores):
|
||||
|
||||
| Span Attribute | Metric Label | Applies To |
|
||||
| ------------------------------ | ------------------------------ | ------------------------------- |
|
||||
| `xrpl.rpc.command` | `xrpl_rpc_command` | `rpc.command.*` spans |
|
||||
| `xrpl.rpc.status` | `xrpl_rpc_status` | `rpc.command.*` spans |
|
||||
| `xrpl.consensus.mode` | `xrpl_consensus_mode` | `consensus.ledger_close` spans |
|
||||
| `xrpl.tx.local` | `xrpl_tx_local` | `tx.process` spans |
|
||||
| `xrpl.peer.proposal.trusted` | `xrpl_peer_proposal_trusted` | `peer.proposal.receive` spans |
|
||||
| `xrpl.peer.validation.trusted` | `xrpl_peer_validation_trusted` | `peer.validation.receive` spans |
|
||||
| Span Attribute | Metric Label | Applies To |
|
||||
| --------------------- | ------------------------------ | ------------------------------- |
|
||||
| `command` | `xrpl_rpc_command` | `rpc.command.*` spans |
|
||||
| `rpc_status` | `xrpl_rpc_status` | `rpc.command.*` spans |
|
||||
| `xrpl.consensus.mode` | `xrpl_consensus_mode` | `consensus.ledger_close` spans |
|
||||
| `local` | `xrpl_tx_local` | `tx.process` spans |
|
||||
| `proposal_trusted` | `xrpl_peer_proposal_trusted` | `peer.proposal.receive` spans |
|
||||
| `validation_trusted` | `xrpl_peer_validation_trusted` | `peer.validation.receive` spans |
|
||||
|
||||
### Histogram Buckets
|
||||
|
||||
|
||||
@@ -53,7 +53,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
|
||||
|
||||
@@ -86,7 +86,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
|
||||
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
* concatenation support. boost::static_string is not constexpr.
|
||||
* StaticStr<N> exists specifically for compile-time dot-join composition.
|
||||
*
|
||||
* Naming conventions follow OpenTelemetry semantic conventions:
|
||||
* - Attribute keys: "xrpl.<subsystem>.<field>"
|
||||
* - Span prefixes: "<subsystem>[.<component>]"
|
||||
* 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: <domain>_<field> when bare name collides across
|
||||
* domains or with OTel reserved `status` (e.g. rpc_status, grpc_status).
|
||||
* - Resource attribute keys: xrpl.<subsystem>.<field> (process-identity).
|
||||
* - Span prefixes: <subsystem>[.<component>].
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
@@ -98,14 +101,27 @@ 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");
|
||||
|
||||
/// 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"));
|
||||
|
||||
/// Canonical shared attrs (rule 5 — kept xrpl.<domain>.* 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"));
|
||||
|
||||
/// 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 =============================================
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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