Merge #10150: [rpc] Add logging rpc
7fd50c3
allow libevent logging to be updated during runtime (John Newbery)5255aca
[rpc] Add logging RPC (John Newbery)4d9950d
Set BCLog::LIBEVENT correctly for old libevent versions. (John Newbery) Tree-SHA512: d6788a7205372c0528da71eca052910dfb055f2940ca884f422ff3db66e23a2b49c6a15b8f27d5255554fe5c5a928f5dd903fdc63b0bd6c8fa7783e77bb30fe8
This commit is contained in:
commit
350b22497c
7 changed files with 123 additions and 12 deletions
|
@ -97,7 +97,7 @@ endif
|
|||
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
|
||||
test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
|
||||
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
|
||||
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS)
|
||||
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
|
||||
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
||||
if ENABLE_WALLET
|
||||
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
|
||||
|
|
|
@ -384,15 +384,13 @@ bool InitHTTPServer()
|
|||
|
||||
// Redirect libevent's logging to our own log
|
||||
event_set_log_callback(&libevent_log_cb);
|
||||
#if LIBEVENT_VERSION_NUMBER >= 0x02010100
|
||||
// If -debug=libevent, set full libevent debugging.
|
||||
// Otherwise, disable all libevent debugging.
|
||||
if (LogAcceptCategory(BCLog::LIBEVENT)) {
|
||||
event_enable_debug_logging(EVENT_DBG_ALL);
|
||||
} else {
|
||||
event_enable_debug_logging(EVENT_DBG_NONE);
|
||||
// Update libevent's log handling. Returns false if our version of
|
||||
// libevent doesn't support debug logging, in which case we should
|
||||
// clear the BCLog::LIBEVENT flag.
|
||||
if (!UpdateHTTPServerLogging(logCategories & BCLog::LIBEVENT)) {
|
||||
logCategories &= ~BCLog::LIBEVENT;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
evthread_use_windows_threads();
|
||||
#else
|
||||
|
@ -435,6 +433,20 @@ bool InitHTTPServer()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool UpdateHTTPServerLogging(bool enable) {
|
||||
#if LIBEVENT_VERSION_NUMBER >= 0x02010100
|
||||
if (enable) {
|
||||
event_enable_debug_logging(EVENT_DBG_ALL);
|
||||
} else {
|
||||
event_enable_debug_logging(EVENT_DBG_NONE);
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
// Can't update libevent logging if version < 02010100
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::thread threadHTTP;
|
||||
std::future<bool> threadResult;
|
||||
|
||||
|
|
|
@ -32,6 +32,10 @@ void InterruptHTTPServer();
|
|||
/** Stop HTTP server */
|
||||
void StopHTTPServer();
|
||||
|
||||
/** Change logging level for libevent. Removes BCLog::LIBEVENT from logCategories if
|
||||
* libevent doesn't support debug logging.*/
|
||||
bool UpdateHTTPServerLogging(bool enable);
|
||||
|
||||
/** Handler for requests to a certain HTTP path */
|
||||
typedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
|
||||
/** Register handler for prefix.
|
||||
|
|
|
@ -113,6 +113,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "getmempoolancestors", 1, "verbose" },
|
||||
{ "getmempooldescendants", 1, "verbose" },
|
||||
{ "bumpfee", 1, "options" },
|
||||
{ "logging", 0, "include" },
|
||||
{ "logging", 1, "exclude" },
|
||||
// Echo with conversion (For testing only)
|
||||
{ "echojson", 0, "arg0" },
|
||||
{ "echojson", 1, "arg1" },
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "clientversion.h"
|
||||
#include "init.h"
|
||||
#include "validation.h"
|
||||
#include "httpserver.h"
|
||||
#include "net.h"
|
||||
#include "netbase.h"
|
||||
#include "rpc/blockchain.h"
|
||||
|
@ -555,6 +556,73 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t getCategoryMask(UniValue cats) {
|
||||
cats = cats.get_array();
|
||||
uint32_t mask = 0;
|
||||
for (unsigned int i = 0; i < cats.size(); ++i) {
|
||||
uint32_t flag = 0;
|
||||
std::string cat = cats[i].get_str();
|
||||
if (!GetLogCategory(&flag, &cat)) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat);
|
||||
}
|
||||
mask |= flag;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
UniValue logging(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() > 2) {
|
||||
throw std::runtime_error(
|
||||
"logging [include,...] <exclude>\n"
|
||||
"Gets and sets the logging configuration.\n"
|
||||
"When called without an argument, returns the list of categories that are currently being debug logged.\n"
|
||||
"When called with arguments, adds or removes categories from debug logging.\n"
|
||||
"The valid logging categories are: " + ListLogCategories() + "\n"
|
||||
"libevent logging is configured on startup and cannot be modified by this RPC during runtime."
|
||||
"Arguments:\n"
|
||||
"1. \"include\" (array of strings) add debug logging for these categories.\n"
|
||||
"2. \"exclude\" (array of strings) remove debug logging for these categories.\n"
|
||||
"\nResult: <categories> (string): a list of the logging categories that are active.\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
|
||||
+ HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")
|
||||
);
|
||||
}
|
||||
|
||||
uint32_t originalLogCategories = logCategories;
|
||||
if (request.params.size() > 0 && request.params[0].isArray()) {
|
||||
logCategories |= getCategoryMask(request.params[0]);
|
||||
}
|
||||
|
||||
if (request.params.size() > 1 && request.params[1].isArray()) {
|
||||
logCategories &= ~getCategoryMask(request.params[1]);
|
||||
}
|
||||
|
||||
// Update libevent logging if BCLog::LIBEVENT has changed.
|
||||
// If the library version doesn't allow it, UpdateHTTPServerLogging() returns false,
|
||||
// in which case we should clear the BCLog::LIBEVENT flag.
|
||||
// Throw an error if the user has explicitly asked to change only the libevent
|
||||
// flag and it failed.
|
||||
uint32_t changedLogCategories = originalLogCategories ^ logCategories;
|
||||
if (changedLogCategories & BCLog::LIBEVENT) {
|
||||
if (!UpdateHTTPServerLogging(logCategories & BCLog::LIBEVENT)) {
|
||||
logCategories &= ~BCLog::LIBEVENT;
|
||||
if (changedLogCategories == BCLog::LIBEVENT) {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UniValue result(UniValue::VOBJ);
|
||||
std::vector<CLogCategoryActive> vLogCatActive = ListActiveLogCategories();
|
||||
for (const auto& logCatActive : vLogCatActive) {
|
||||
result.pushKV(logCatActive.category, logCatActive.active);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue echo(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp)
|
||||
|
@ -581,7 +649,8 @@ static const CRPCCommand commands[] =
|
|||
/* Not shown in help */
|
||||
{ "hidden", "setmocktime", &setmocktime, true, {"timestamp"}},
|
||||
{ "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
|
||||
{ "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
|
||||
{ "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
|
||||
{ "hidden", "logging", &logging, true, {"include", "exclude"}},
|
||||
};
|
||||
|
||||
void RegisterMiscRPCCommands(CRPCTable &t)
|
||||
|
|
17
src/util.cpp
17
src/util.cpp
|
@ -118,7 +118,7 @@ bool fLogIPs = DEFAULT_LOGIPS;
|
|||
std::atomic<bool> fReopenDebugLog(false);
|
||||
CTranslationInterface translationInterface;
|
||||
|
||||
/** Log categories bitfield. Leveldb/libevent need special handling if their flags are changed at runtime. */
|
||||
/** Log categories bitfield. */
|
||||
std::atomic<uint32_t> logCategories(0);
|
||||
|
||||
/** Init OpenSSL library multithreading support */
|
||||
|
@ -295,6 +295,21 @@ std::string ListLogCategories()
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::vector<CLogCategoryActive> ListActiveLogCategories()
|
||||
{
|
||||
std::vector<CLogCategoryActive> ret;
|
||||
for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
|
||||
// Omit the special cases.
|
||||
if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
|
||||
CLogCategoryActive catActive;
|
||||
catActive.category = LogCategories[i].category;
|
||||
catActive.active = LogAcceptCategory(LogCategories[i].flag);
|
||||
ret.push_back(catActive);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* fStartedNewLine is a state variable held by the calling context that will
|
||||
* suppress printing of the timestamp when multiple calls are made that don't
|
||||
|
|
11
src/util.h
11
src/util.h
|
@ -69,6 +69,12 @@ inline std::string _(const char* psz)
|
|||
void SetupEnvironment();
|
||||
bool SetupNetworking();
|
||||
|
||||
struct CLogCategoryActive
|
||||
{
|
||||
std::string category;
|
||||
bool active;
|
||||
};
|
||||
|
||||
namespace BCLog {
|
||||
enum LogFlags : uint32_t {
|
||||
NONE = 0,
|
||||
|
@ -102,9 +108,12 @@ static inline bool LogAcceptCategory(uint32_t category)
|
|||
return (logCategories.load(std::memory_order_relaxed) & category) != 0;
|
||||
}
|
||||
|
||||
/** Returns a string with the supported log categories */
|
||||
/** Returns a string with the log categories. */
|
||||
std::string ListLogCategories();
|
||||
|
||||
/** Returns a vector of the active log categories. */
|
||||
std::vector<CLogCategoryActive> ListActiveLogCategories();
|
||||
|
||||
/** Return true if str parses as a log category and set the flags in f */
|
||||
bool GetLogCategory(uint32_t *f, const std::string *str);
|
||||
|
||||
|
|
Loading…
Reference in a new issue