feat(telemetry): enrich RPC and PathFind spans with workflow-identifying attributes

Wire up span attributes that enable filtering/grouping traces by request
characteristics: batch detection, payload size, resource cost category,
command name on WS spans, and pathfinding search parameters (destination
amount/currency, source asset count).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Pratik Mankawde
2026-06-03 15:46:40 +01:00
parent 7bc6c65bb2
commit 84fc829be3
5 changed files with 34 additions and 1 deletions

View File

@@ -84,6 +84,12 @@ inline constexpr auto numPaths = makeStr("pathfind_num_paths");
inline constexpr auto numRequests = makeStr("pathfind_num_requests");
/// "pathfind_ledger_index" — pathfind target ledger index.
inline constexpr auto ledgerIndex = makeStr("pathfind_ledger_index");
/// "pathfind_dest_amount" — requested destination amount as string.
inline constexpr auto destAmount = makeStr("pathfind_dest_amount");
/// "pathfind_dest_currency" — destination currency code.
inline constexpr auto destCurrency = makeStr("pathfind_dest_currency");
/// "pathfind_num_source_assets" — candidate source assets count.
inline constexpr auto numSourceAssets = makeStr("pathfind_num_source_assets");
} // namespace attr
} // namespace xrpl::telemetry::pathfind_span

View File

@@ -594,6 +594,8 @@ PathRequest::findPaths(
auto span = SpanGuard::span(
TraceCategory::Rpc, pathfind_span::prefix::pathfind, pathfind_span::op::discover);
span.setAttribute(pathfind_span::attr::searchLevel, static_cast<int64_t>(level));
span.setAttribute(
pathfind_span::attr::numSourceAssets, static_cast<int64_t>(sourceAssets.size()));
std::int64_t totalPaths = 0;
for (auto const& asset : sourceAssets)
@@ -740,6 +742,8 @@ PathRequest::doUpdate(
auto span = SpanGuard::span(
TraceCategory::Rpc, pathfind_span::prefix::pathfind, pathfind_span::op::compute);
span.setAttribute(pathfind_span::attr::fast, fast);
span.setAttribute(pathfind_span::attr::destAmount, saDstAmount_.getFullText().c_str());
span.setAttribute(pathfind_span::attr::destCurrency, to_string(saDstAmount_.asset()).c_str());
JLOG(journal_.debug()) << iIdentifier_ << " update " << (fast ? "fast" : "normal");

View File

@@ -185,6 +185,7 @@ callMethod(JsonContext& context, Method method, std::string const& name, Object&
JLOG(context.j.debug()) << "RPC call " << name << " completed in "
<< ((end - start).count() / 1000000000.0) << "seconds";
perfLog.rpcFinish(name, curId);
span.setAttribute(rpc_span::attr::loadType, context.loadType.label().c_str());
// Status::operator bool() returns true when there IS an error
// (code_ != OK), so the ternary correctly maps error->error, ok->success.
span.setAttribute(

View File

@@ -144,6 +144,12 @@ inline constexpr auto rpcRole = makeStr("rpc_role");
inline constexpr auto rpcStatus = makeStr("rpc_status");
/// "request_payload_size" — bytes of inbound request payload.
inline constexpr auto requestPayloadSize = makeStr("request_payload_size");
/// "is_batch" — whether request is a JSON-RPC batch.
inline constexpr auto isBatch = makeStr("is_batch");
/// "batch_size" — number of sub-requests in a batch.
inline constexpr auto batchSize = makeStr("batch_size");
/// "load_type" — resource cost category after execution.
inline constexpr auto loadType = makeStr("load_type");
} // namespace attr
// ===== Attribute values ====================================================

View File

@@ -63,6 +63,7 @@
#include <algorithm>
#include <cctype>
#include <chrono>
#include <cstdint>
#include <exception>
#include <map>
#include <memory>
@@ -428,6 +429,15 @@ ServerHandler::processSession(
json::Value const& jv)
{
auto span = SpanGuard::span(TraceCategory::Rpc, rpc_span::prefix::rpc, rpc_span::op::wsMessage);
if (jv.isMember(jss::command) && jv[jss::command].isString())
{
span.setAttribute(rpc_span::attr::command, jv[jss::command].asString().c_str());
}
else if (jv.isMember(jss::method) && jv[jss::method].isString())
{
span.setAttribute(rpc_span::attr::command, jv[jss::method].asString().c_str());
}
auto is = std::static_pointer_cast<WSInfoSub>(session->appDefined);
if (is->getConsumer().disconnect(journal_))
{
@@ -576,9 +586,12 @@ ServerHandler::processSession(
auto span =
SpanGuard::span(TraceCategory::Rpc, rpc_span::prefix::rpc, rpc_span::op::httpRequest);
auto const requestBody = ::xrpl::buffersToString(session->request().body().data());
span.setAttribute(rpc_span::attr::requestPayloadSize, static_cast<int64_t>(requestBody.size()));
processRequest(
session->port(),
::xrpl::buffersToString(session->request().body().data()),
requestBody,
session->remoteAddress().atPort(0),
makeOutput(*session),
coro,
@@ -657,6 +670,9 @@ ServerHandler::processRequest(
}
size = jsonOrig[jss::params].size();
}
span.setAttribute(rpc_span::attr::isBatch, batch);
if (batch)
span.setAttribute(rpc_span::attr::batchSize, static_cast<int64_t>(size));
json::Value reply(batch ? json::ValueType::Array : json::ValueType::Object);
auto const start(std::chrono::high_resolution_clock::now());