feat: Metrics for requested ledger age (#2947)

Adding metrics to be able to analyse requested ledger age distribution.

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Sergey Kuznetsov
2026-02-20 18:01:15 +00:00
committed by GitHub
parent 6ba58f42f0
commit 2d6f82c27f
9 changed files with 224 additions and 14 deletions

View File

@@ -21,18 +21,24 @@
#include "rpc/JS.hpp"
#include "rpc/WorkQueue.hpp"
#include "util/JsonUtils.hpp"
#include "util/prometheus/Label.hpp"
#include "util/prometheus/Prometheus.hpp"
#include <boost/json/object.hpp>
#include <boost/json/value.hpp>
#include <boost/json/value_to.hpp>
#include <fmt/format.h>
#include <xrpl/protocol/jss.h>
#include <chrono>
#include <cstdint>
#include <functional>
#include <mutex>
#include <optional>
#include <string>
#include <utility>
#include <vector>
namespace rpc {
@@ -138,6 +144,21 @@ Counters::Counters(Reportable const& wq)
"Total number of internal errors"
)
)
, ledgerAgeLedgersHistogram_(
PrometheusService::histogramInt(
"rpc_requested_ledger_age_histogram",
Labels{},
{0, 10, 100, 1'000, 10'000, 100'000, 1'000'000, 10'000'000, 100'000'000},
"Age of requested ledgers in ledger count"
)
)
, ledgerHashRequestsCounter_(
PrometheusService::counterInt(
"rpc_ledger_hash_requests_total_number",
Labels{},
"Total number of successful requests containing ledger_hash field"
)
)
, workQueue_(std::cref(wq))
, startupTime_{std::chrono::system_clock::now()}
{
@@ -217,6 +238,35 @@ Counters::onInternalError()
++internalErrorCounter_.get();
}
void
Counters::recordLedgerRequest(
boost::json::object const& params,
std::uint32_t currentLedgerSequence
)
{
if (params.contains(JS(ledger_hash))) {
++ledgerHashRequestsCounter_.get();
return;
}
if (not params.contains(JS(ledger_index))) {
ledgerAgeLedgersHistogram_.get().observe(0);
return;
}
auto const& indexValue = params.at("ledger_index");
if (auto const parsed = util::getLedgerIndex(indexValue); parsed.has_value()) {
if (*parsed <= currentLedgerSequence) {
auto const ageLedgers = static_cast<std::int64_t>(currentLedgerSequence - *parsed);
ledgerAgeLedgersHistogram_.get().observe(ageLedgers);
}
} else if (indexValue.is_string()) {
auto const indexStr = boost::json::value_to<std::string>(indexValue);
if (indexStr == "validated") {
ledgerAgeLedgersHistogram_.get().observe(0);
}
}
}
std::chrono::seconds
Counters::uptime() const
{

View File

@@ -21,11 +21,13 @@
#include "rpc/WorkQueue.hpp"
#include "util/prometheus/Counter.hpp"
#include "util/prometheus/Histogram.hpp"
#include <boost/json.hpp>
#include <boost/json/object.hpp>
#include <chrono>
#include <cstdint>
#include <functional>
#include <mutex>
#include <string>
@@ -66,6 +68,9 @@ class Counters {
CounterType unknownCommandCounter_;
CounterType internalErrorCounter_;
std::reference_wrapper<util::prometheus::HistogramInt> ledgerAgeLedgersHistogram_;
CounterType ledgerHashRequestsCounter_;
std::reference_wrapper<Reportable const> workQueue_;
std::chrono::time_point<std::chrono::system_clock> startupTime_;
@@ -150,6 +155,15 @@ public:
void
onInternalError();
/**
* @brief Records ledger request metrics based on the ledger parameter in the request.
*
* @param params The request parameters containing ledger information
* @param currentLedgerSequence The current ledger sequence number
*/
void
recordLedgerRequest(boost::json::object const& params, std::uint32_t currentLedgerSequence);
/** @return Uptime of this instance in seconds. */
std::chrono::seconds
uptime() const;

View File

@@ -27,7 +27,6 @@
#include "rpc/common/HandlerProvider.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/impl/ForwardingProxy.hpp"
#include "util/OverloadSet.hpp"
#include "util/ResponseExpirationCache.hpp"
#include "util/log/Logger.hpp"
#include "web/Context.hpp"
@@ -41,6 +40,7 @@
#include <xrpl/protocol/ErrorCodes.h>
#include <chrono>
#include <cstdint>
#include <exception>
#include <functional>
#include <memory>
@@ -228,16 +228,37 @@ public:
}
/**
* @brief Notify the system that specified method was executed.
* @brief Notify the system that specified method was executed and record ledger metrics.
*
* @param method
* @param context The web context containing method, params, and ledger information
* @param duration The time it took to execute the method specified in microseconds
* @param isForwarded Whether the request was forwarded to rippled or not
*/
void
notifyComplete(std::string const& method, std::chrono::microseconds const& duration)
notifyComplete(
web::Context const& context,
std::chrono::microseconds const& duration,
bool isForwarded
)
{
if (validHandler(method))
counters_.get().rpcComplete(method, duration);
if (validHandler(context.method)) {
counters_.get().rpcComplete(context.method, duration);
if (not isForwarded) {
counters_.get().recordLedgerRequest(context.params, context.range.maxSequence);
}
}
}
/**
* @brief Record ledger request metrics.
*
* @param params The request parameters containing ledger information
* @param currentLedgerSequence The current ledger sequence
*/
void
recordLedgerMetrics(boost::json::object const& params, std::uint32_t currentLedgerSequence)
{
counters_.get().recordLedgerRequest(params, currentLedgerSequence);
}
/**