71 static constexpr auto kBACKEND_COUNTERS_KEY =
"backend_counters";
73 std::shared_ptr<BackendInterface> backend_;
74 std::shared_ptr<feed::SubscriptionManagerInterface> subscriptions_;
75 std::shared_ptr<LoadBalancerType> balancer_;
76 std::shared_ptr<ETLServiceType const> etl_;
77 std::reference_wrapper<CountersType const> counters_;
84 bool backendCounters =
false;
91 boost::json::object counters;
92 std::optional<boost::json::object> backendCounters;
93 boost::json::object subscriptions;
94 boost::json::object
etl;
103 ripple::LedgerIndex seq = {};
104 std::optional<ripple::Fees> fees = std::nullopt;
111 std::size_t size = 0;
112 bool isEnabled =
false;
114 ripple::LedgerIndex latestLedgerSeq = {};
115 float objectHitRate = 1.0;
116 float successorHitRate = 1.0;
123 std::optional<AdminSection> adminSection = std::nullopt;
124 std::string completeLedgers;
125 uint32_t loadFactor = 1u;
126 std::chrono::time_point<std::chrono::system_clock> time = std::chrono::system_clock::now();
127 std::chrono::seconds uptime = {};
128 std::string clioVersion = util::build::getClioVersionString();
129 std::string xrplVersion = ripple::BuildInfo::getVersionString();
130 std::optional<boost::json::object> rippledInfo = std::nullopt;
133 bool isAmendmentBlocked =
false;
134 bool isCorruptionDetected =
false;
144 bool validated =
true;
159 std::shared_ptr<BackendInterface>
const& backend,
160 std::shared_ptr<feed::SubscriptionManagerInterface>
const& subscriptions,
161 std::shared_ptr<LoadBalancerType>
const& balancer,
162 std::shared_ptr<ETLServiceType const>
const&
etl,
163 CountersType
const& counters
166 , subscriptions_(subscriptions)
167 , balancer_(balancer)
169 , counters_(std::cref(counters))
180 spec([[maybe_unused]] uint32_t apiVersion)
182 static RpcSpec const kRPC_SPEC = {};
197 using namespace std::chrono;
199 auto const range = backend_->fetchLedgerRange();
200 ASSERT(range.has_value(),
"ServerInfo's ledger range must be available");
202 auto const lgrInfo = backend_->fetchLedgerBySequence(range->maxSequence, ctx.yield);
203 if (not lgrInfo.has_value())
206 auto const fees = backend_->fetchFees(lgrInfo->seq, ctx.yield);
207 if (not fees.has_value())
211 auto const sinceEpoch = duration_cast<seconds>(system_clock::now().time_since_epoch()).count();
212 auto const age =
static_cast<int32_t
>(sinceEpoch) -
213 static_cast<int32_t
>(lgrInfo->closeTime.time_since_epoch().count()) -
216 output.info.completeLedgers = fmt::format(
"{}-{}", range->minSequence, range->maxSequence);
219 output.info.adminSection = {
220 .counters = counters_.get().report(),
221 .backendCounters = input.backendCounters ? std::make_optional(backend_->stats()) : std::nullopt,
222 .subscriptions = subscriptions_->report(),
223 .etl = etl_->getInfo()
227 auto const serverInfoRippled =
228 balancer_->forwardToRippled({{
"command",
"server_info"}}, ctx.clientIp, ctx.isAdmin, ctx.yield);
230 if (serverInfoRippled && !serverInfoRippled->contains(JS(error))) {
231 if (serverInfoRippled->contains(JS(result)) &&
232 serverInfoRippled->at(JS(result)).as_object().contains(JS(info))) {
233 output.info.rippledInfo = serverInfoRippled->at(JS(result)).as_object().at(JS(info)).as_object();
237 output.info.validatedLedger.age = age < 0 ? 0 : age;
238 output.info.validatedLedger.hash = ripple::strHex(lgrInfo->hash);
239 output.info.validatedLedger.seq = lgrInfo->seq;
240 output.info.validatedLedger.fees = fees;
241 output.info.cache.size = backend_->cache().size();
242 output.info.cache.isFull = backend_->cache().isFull();
243 output.info.cache.latestLedgerSeq = backend_->cache().latestLedgerSequence();
244 output.info.cache.objectHitRate = backend_->cache().getObjectHitRate();
245 output.info.cache.successorHitRate = backend_->cache().getSuccessorHitRate();
246 output.info.cache.isEnabled = not backend_->cache().isDisabled();
247 output.info.uptime = counters_.get().uptime();
248 output.info.isAmendmentBlocked = etl_->isAmendmentBlocked();
249 output.info.isCorruptionDetected = etl_->isCorruptionDetected();
256 tag_invoke(boost::json::value_from_tag, boost::json::value& jv, Output
const& output)
258 using boost::json::value_from;
261 {JS(info), value_from(output.info)},
262 {JS(validated), output.validated},
267 tag_invoke(boost::json::value_from_tag, boost::json::value& jv, InfoSection
const& info)
269 using boost::json::value_from;
270 using ripple::to_string;
273 {JS(complete_ledgers), info.completeLedgers},
274 {JS(load_factor), info.loadFactor},
275 {JS(time), to_string(std::chrono::floor<std::chrono::microseconds>(info.time))},
276 {JS(uptime), info.uptime.count()},
277 {
"clio_version", info.clioVersion},
278 {
"libxrpl_version", info.xrplVersion},
279 {JS(validated_ledger), value_from(info.validatedLedger)},
280 {
"cache", value_from(info.cache)},
283 if (info.isAmendmentBlocked)
284 jv.as_object()[JS(amendment_blocked)] =
true;
286 if (info.isCorruptionDetected)
287 jv.as_object()[
"corruption_detected"] =
true;
289 if (info.rippledInfo) {
290 auto const& rippledInfo = info.rippledInfo.value();
292 if (rippledInfo.contains(JS(load_factor)))
293 jv.as_object()[JS(load_factor)] = rippledInfo.at(JS(load_factor));
294 if (rippledInfo.contains(JS(validation_quorum)))
295 jv.as_object()[JS(validation_quorum)] = rippledInfo.at(JS(validation_quorum));
296 if (rippledInfo.contains(JS(build_version)))
297 jv.as_object()[
"rippled_version"] = rippledInfo.at(JS(build_version));
298 if (rippledInfo.contains(JS(network_id)))
299 jv.as_object()[JS(network_id)] = rippledInfo.at(JS(network_id));
302 if (info.adminSection) {
303 jv.as_object()[
"etl"] = info.adminSection->etl;
304 jv.as_object()[JS(counters)] = info.adminSection->counters;
305 jv.as_object()[JS(counters)].as_object()[
"subscriptions"] = info.adminSection->subscriptions;
306 if (info.adminSection->backendCounters.has_value()) {
307 jv.as_object()[kBACKEND_COUNTERS_KEY] = *info.adminSection->backendCounters;
313 tag_invoke(boost::json::value_from_tag, boost::json::value& jv, ValidatedLedgerSection
const& validated)
316 {JS(age), validated.age},
317 {JS(hash), validated.hash},
318 {JS(seq), validated.seq},
319 {JS(base_fee_xrp), validated.fees->base.decimalXRP()},
320 {JS(reserve_base_xrp), validated.fees->reserve.decimalXRP()},
321 {JS(reserve_inc_xrp), validated.fees->increment.decimalXRP()},
326 tag_invoke(boost::json::value_from_tag, boost::json::value& jv, CacheSection
const& cache)
329 {
"size", cache.size},
330 {
"is_enabled", cache.isEnabled},
331 {
"is_full", cache.isFull},
332 {
"latest_ledger_seq", cache.latestLedgerSeq},
333 {
"object_hit_rate", cache.objectHitRate},
334 {
"successor_hit_rate", cache.successorHitRate},
339 tag_invoke(boost::json::value_to_tag<Input>, boost::json::value
const& jv)
342 auto const jsonObject = jv.as_object();
343 if (jsonObject.contains(kBACKEND_COUNTERS_KEY) && jsonObject.at(kBACKEND_COUNTERS_KEY).is_bool())
344 input.backendCounters = jv.at(kBACKEND_COUNTERS_KEY).as_bool();
BaseServerInfoHandler(std::shared_ptr< BackendInterface > const &backend, std::shared_ptr< feed::SubscriptionManagerInterface > const &subscriptions, std::shared_ptr< LoadBalancerType > const &balancer, std::shared_ptr< ETLServiceType const > const &etl, CountersType const &counters)
Construct a new BaseServerInfoHandler object.
Definition ServerInfo.hpp:158