From d2f1badd373b96ce4fa0027dc2173d8d977a8505 Mon Sep 17 00:00:00 2001 From: Howard Hinnant <howard.hinnant@gmail.com> Date: Mon, 6 Apr 2020 17:22:19 -0400 Subject: [PATCH] Create health_check rpc * Gives a summary of the health of the node: Healthy, Warning, or Critical * Last validated ledger age: <7s is Healthy, 7s to 20s is Warning > 20s is Critcal * If amendment blocked, Critical * Number of peers: > 7 is Healthy 1 to 7 is Warning 0 is Critical * server state: One of full, validating or proposing is Healthy One of syncing, tracking or connected is Warning All other states are Critical * load factor: <= 100 is Healthy 101 to 999 is Warning >= 1000 is Critical * If not Healthy, info field contains data that is considered not Healthy. Fixes: #2809 --- Builds/CMake/RippledCore.cmake | 1 + src/ripple/app/main/Main.cpp | 1 + src/ripple/net/impl/RPCCall.cpp | 1 + src/ripple/rpc/handlers/Handlers.h | 2 + src/ripple/rpc/handlers/HealthCheck.cpp | 119 ++++++++++++++++++++++++ src/ripple/rpc/impl/Handler.cpp | 1 + 6 files changed, 125 insertions(+) create mode 100644 src/ripple/rpc/handlers/HealthCheck.cpp diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index 5dffaade794..1860c6afcee 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -573,6 +573,7 @@ target_sources (rippled PRIVATE src/ripple/rpc/handlers/FetchInfo.cpp src/ripple/rpc/handlers/GatewayBalances.cpp src/ripple/rpc/handlers/GetCounts.cpp + src/ripple/rpc/handlers/HealthCheck.cpp src/ripple/rpc/handlers/LedgerAccept.cpp src/ripple/rpc/handlers/LedgerCleanerHandler.cpp src/ripple/rpc/handlers/LedgerClosed.cpp diff --git a/src/ripple/app/main/Main.cpp b/src/ripple/app/main/Main.cpp index 527f86f19f2..51f80c4f465 100644 --- a/src/ripple/app/main/Main.cpp +++ b/src/ripple/app/main/Main.cpp @@ -148,6 +148,7 @@ printHelp(const po::options_description& desc) " gateway_balances [<ledger>] <issuer_account> [ <hotwallet> [ " "<hotwallet> ]]\n" " get_counts\n" + " health_check\n" " json <method> <json>\n" " ledger [<id>|current|closed|validated] [full]\n" " ledger_accept\n" diff --git a/src/ripple/net/impl/RPCCall.cpp b/src/ripple/net/impl/RPCCall.cpp index a565d4bc321..5999c80b88e 100644 --- a/src/ripple/net/impl/RPCCall.cpp +++ b/src/ripple/net/impl/RPCCall.cpp @@ -1237,6 +1237,7 @@ class RPCParser {"fetch_info", &RPCParser::parseFetchInfo, 0, 1}, {"gateway_balances", &RPCParser::parseGatewayBalances, 1, -1}, {"get_counts", &RPCParser::parseGetCounts, 0, 1}, + {"health_check", &RPCParser::parseAsIs, 0, 0}, {"json", &RPCParser::parseJson, 2, 2}, {"json2", &RPCParser::parseJson2, 1, 1}, {"ledger", &RPCParser::parseLedger, 0, 2}, diff --git a/src/ripple/rpc/handlers/Handlers.h b/src/ripple/rpc/handlers/Handlers.h index b9c47be9db5..38ba24e2ee6 100644 --- a/src/ripple/rpc/handlers/Handlers.h +++ b/src/ripple/rpc/handlers/Handlers.h @@ -71,6 +71,8 @@ doGatewayBalances(RPC::JsonContext&); Json::Value doGetCounts(RPC::JsonContext&); Json::Value +doHealthCheck(RPC::JsonContext&); +Json::Value doLedgerAccept(RPC::JsonContext&); Json::Value doLedgerCleaner(RPC::JsonContext&); diff --git a/src/ripple/rpc/handlers/HealthCheck.cpp b/src/ripple/rpc/handlers/HealthCheck.cpp new file mode 100644 index 00000000000..06128b7c83e --- /dev/null +++ b/src/ripple/rpc/handlers/HealthCheck.cpp @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012-2014 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include <ripple/app/misc/NetworkOPs.h> +#include <ripple/json/json_value.h> +#include <ripple/net/RPCErr.h> +#include <ripple/protocol/jss.h> +#include <ripple/rpc/Context.h> +#include <ripple/rpc/impl/TransactionSign.h> +#include <ripple/rpc/Role.h> + +namespace ripple { + +Json::Value +doHealthCheck(RPC::JsonContext& context) +{ + bool constexpr humanReadable = true; + bool constexpr noAdmin = false; + bool constexpr noCounters = false; + auto info = context.netOps.getServerInfo( + humanReadable, noAdmin, noCounters); + + int last_validated_ledger_age = std::numeric_limits<int>::max(); + if (info.isMember("validated_ledger")) + last_validated_ledger_age = info["validated_ledger"]["age"].asInt(); + bool amendment_blocked = false; + if (info.isMember("amendment_blocked")) + amendment_blocked = true; + int number_peers = info["peers"].asInt(); + std::string server_state = info["server_state"].asString(); + auto load_factor = info["load_factor"].asDouble(); + + Json::Value ret = Json::objectValue; + enum {healthy, warning, critical}; + int health = healthy; + auto set_health = [&health](int state) + { + if (health < state) + health = state; + }; + + if (last_validated_ledger_age >= 7) + { + ret[jss::info]["validated_ledger"] = last_validated_ledger_age; + if (last_validated_ledger_age < 20) + set_health(warning); + else + set_health(critical); + } + + if (amendment_blocked) + { + ret[jss::info]["amendment_blocked"] = true; + set_health(critical); + } + + if (number_peers <= 7) + { + ret[jss::info]["peers"] = number_peers; + if (number_peers != 0) + set_health(warning); + else + set_health(critical); + } + + if (!(server_state == "full" || server_state == "validating" || + server_state == "proposing")) + { + ret[jss::info]["server_state"] = server_state; + if (server_state == "syncing" || server_state == "tracking" || + server_state == "connected") + { + set_health(warning); + } + else + set_health(critical); + } + + if (load_factor > 100) + { + ret[jss::info]["load_factor"] = load_factor; + if (load_factor < 1000) + set_health(warning); + else + set_health(critical); + } + + switch (health) + { + case healthy: + ret["health"] = "Healthy"; + break; + case warning: + ret["health"] = "Warning"; + break; + default: + ret["health"] = "Critical"; + break; + } + return ret; +} + +} // ripple diff --git a/src/ripple/rpc/impl/Handler.cpp b/src/ripple/rpc/impl/Handler.cpp index b5fa9978540..4249699d465 100644 --- a/src/ripple/rpc/impl/Handler.cpp +++ b/src/ripple/rpc/impl/Handler.cpp @@ -87,6 +87,7 @@ Handler const handlerArray[]{ {"feature", byRef(&doFeature), Role::ADMIN, NO_CONDITION}, {"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER}, {"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION}, + {"health_check", byRef(&doHealthCheck), Role::USER, NO_CONDITION}, {"ledger_accept", byRef(&doLedgerAccept), Role::ADMIN,