Merge #14982: rpc: Add getrpcinfo command

a0ac15459a0df598e1ee1fd36a3899a129cecaeb doc: Add getrpcinfo release notes (João Barbosa)
251a91c1bf245b3674c2612149382a0f1e18dc98 qa: Add tests for getrpcinfo (João Barbosa)
d0730f5ce475e5a84da7c61fe79bcd6ed24d693e rpc: Add getrpcinfo command (João Barbosa)
068a8fc05f8dbec198bdc3fe46f955d8a5255303 rpc: Track active commands (João Barbosa)
bf4383277d6761cc5b7a91975752c08df829af72 rpc: Remove unused PreCommand signal (João Barbosa)

Pull request description:

  The new `getrpcinfo` command exposes details of the RPC interface. The details can be configuration properties or runtime values/stats.

  This can be particular useful to coordinate concurrent functional tests (see #14958 from where this was extracted).

Tree-SHA512: 7292cb6087f4c429973d991aa2b53ffa1327d5a213df7d6ba5fc69b01b2e1a411f6d1609fed9234896293317dab05f65064da48b8f2b4a998eba532591d31882
This commit is contained in:
Wladimir J. van der Laan 2019-01-14 18:05:26 +01:00 committed by munkybooty
parent 744ebbed3a
commit e54d4af104
3 changed files with 76 additions and 1 deletions

View File

@ -0,0 +1,5 @@
New RPCs
--------
- The RPC `getrpcinfo` returns runtime details of the RPC server. At the moment
it returns the active commands and the corresponding execution time.

View File

@ -35,6 +35,35 @@ static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& req
// Any commands submitted by this user will have their commands filtered based on the mapPlatformRestrictions
static const std::string defaultPlatformUser = "platform-user";
struct RPCCommandExecutionInfo
{
std::string method;
int64_t start;
};
struct RPCServerInfo
{
Mutex mutex;
std::list<RPCCommandExecutionInfo> active_commands GUARDED_BY(mutex);
};
static RPCServerInfo g_rpc_server_info;
struct RPCCommandExecution
{
std::list<RPCCommandExecutionInfo>::iterator it;
explicit RPCCommandExecution(const std::string& method)
{
LOCK(g_rpc_server_info.mutex);
it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.cend(), {method, GetTimeMicros()});
}
~RPCCommandExecution()
{
LOCK(g_rpc_server_info.mutex);
g_rpc_server_info.active_commands.erase(it);
}
};
static struct CRPCSignals
{
boost::signals2::signal<void ()> Started;
@ -191,11 +220,40 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest)
return GetTime() - GetStartupTime();
}
static UniValue getrpcinfo(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 0) {
throw std::runtime_error(
RPCHelpMan{"getrpcinfo",
"\nReturns details of the RPC server.\n",
{},
RPCResults{},
RPCExamples{""},
}.ToString()
);
}
LOCK(g_rpc_server_info.mutex);
UniValue active_commands(UniValue::VARR);
for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) {
UniValue entry(UniValue::VOBJ);
entry.pushKV("method", info.method);
entry.pushKV("duration", GetTimeMicros() - info.start);
active_commands.push_back(entry);
}
UniValue result(UniValue::VOBJ);
result.pushKV("active_commands", active_commands);
return result;
}
// clang-format off
static const CRPCCommand vRPCCommands[] =
{ // category name actor (function) argNames
// --------------------- ------------------------ ----------------------- ----------
/* Overall control/query calls */
{ "control", "getrpcinfo", &getrpcinfo, {} },
{ "control", "help", &help, {"command","subcommand"} },
{ "control", "stop", &stop, {"wait"} },
{ "control", "uptime", &uptime, {} },
@ -495,6 +553,7 @@ static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& req
try
{
RPCCommandExecution execution(request.strMethod);
// Execute, convert arguments to array if necessary
if (request.params.isObject()) {
return command.actor(transformNamedArguments(request, command.argNames), result, last_handler);

View File

@ -6,7 +6,7 @@
from test_framework.authproxy import JSONRPCException
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.util import assert_equal, assert_greater_than_or_equal
def expect_http_status(expected_http_status, expected_rpc_code,
fcn, *args):
@ -22,6 +22,16 @@ class RPCInterfaceTest(BitcoinTestFramework):
self.num_nodes = 1
self.setup_clean_chain = True
def test_getrpcinfo(self):
self.log.info("Testing getrpcinfo...")
info = self.nodes[0].getrpcinfo()
assert_equal(len(info['active_commands']), 1)
command = info['active_commands'][0]
assert_equal(command['method'], 'getrpcinfo')
assert_greater_than_or_equal(command['duration'], 0)
def test_batch_request(self):
self.log.info("Testing basic JSON-RPC batch request...")
@ -55,6 +65,7 @@ class RPCInterfaceTest(BitcoinTestFramework):
expect_http_status(500, -8, self.nodes[0].getblockhash, 42)
def run_test(self):
self.test_getrpcinfo()
self.test_batch_request()
self.test_http_status_codes()