Browse Source

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
0.15
Wladimir J. van der Laan 8 years ago
parent
commit
350b22497c
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 2
      src/Makefile.test.include
  2. 28
      src/httpserver.cpp
  3. 4
      src/httpserver.h
  4. 2
      src/rpc/client.cpp
  5. 71
      src/rpc/misc.cpp
  6. 17
      src/util.cpp
  7. 11
      src/util.h

2
src/Makefile.test.include

@ -97,7 +97,7 @@ endif
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) 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_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) \ 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) test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
if ENABLE_WALLET if ENABLE_WALLET
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)

28
src/httpserver.cpp

@ -384,15 +384,13 @@ bool InitHTTPServer()
// Redirect libevent's logging to our own log // Redirect libevent's logging to our own log
event_set_log_callback(&libevent_log_cb); event_set_log_callback(&libevent_log_cb);
#if LIBEVENT_VERSION_NUMBER >= 0x02010100 // Update libevent's log handling. Returns false if our version of
// If -debug=libevent, set full libevent debugging. // libevent doesn't support debug logging, in which case we should
// Otherwise, disable all libevent debugging. // clear the BCLog::LIBEVENT flag.
if (LogAcceptCategory(BCLog::LIBEVENT)) { if (!UpdateHTTPServerLogging(logCategories & BCLog::LIBEVENT)) {
event_enable_debug_logging(EVENT_DBG_ALL); logCategories &= ~BCLog::LIBEVENT;
} else {
event_enable_debug_logging(EVENT_DBG_NONE);
} }
#endif
#ifdef WIN32 #ifdef WIN32
evthread_use_windows_threads(); evthread_use_windows_threads();
#else #else
@ -435,6 +433,20 @@ bool InitHTTPServer()
return true; 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::thread threadHTTP;
std::future<bool> threadResult; std::future<bool> threadResult;

4
src/httpserver.h

@ -32,6 +32,10 @@ void InterruptHTTPServer();
/** Stop HTTP server */ /** Stop HTTP server */
void StopHTTPServer(); 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 */ /** Handler for requests to a certain HTTP path */
typedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHandler; typedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
/** Register handler for prefix. /** Register handler for prefix.

2
src/rpc/client.cpp

@ -113,6 +113,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "getmempoolancestors", 1, "verbose" }, { "getmempoolancestors", 1, "verbose" },
{ "getmempooldescendants", 1, "verbose" }, { "getmempooldescendants", 1, "verbose" },
{ "bumpfee", 1, "options" }, { "bumpfee", 1, "options" },
{ "logging", 0, "include" },
{ "logging", 1, "exclude" },
// Echo with conversion (For testing only) // Echo with conversion (For testing only)
{ "echojson", 0, "arg0" }, { "echojson", 0, "arg0" },
{ "echojson", 1, "arg1" }, { "echojson", 1, "arg1" },

71
src/rpc/misc.cpp

@ -7,6 +7,7 @@
#include "clientversion.h" #include "clientversion.h"
#include "init.h" #include "init.h"
#include "validation.h" #include "validation.h"
#include "httpserver.h"
#include "net.h" #include "net.h"
#include "netbase.h" #include "netbase.h"
#include "rpc/blockchain.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) UniValue echo(const JSONRPCRequest& request)
{ {
if (request.fHelp) if (request.fHelp)
@ -581,7 +649,8 @@ static const CRPCCommand commands[] =
/* Not shown in help */ /* Not shown in help */
{ "hidden", "setmocktime", &setmocktime, true, {"timestamp"}}, { "hidden", "setmocktime", &setmocktime, true, {"timestamp"}},
{ "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, { "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) void RegisterMiscRPCCommands(CRPCTable &t)

17
src/util.cpp

@ -118,7 +118,7 @@ bool fLogIPs = DEFAULT_LOGIPS;
std::atomic<bool> fReopenDebugLog(false); std::atomic<bool> fReopenDebugLog(false);
CTranslationInterface translationInterface; 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); std::atomic<uint32_t> logCategories(0);
/** Init OpenSSL library multithreading support */ /** Init OpenSSL library multithreading support */
@ -295,6 +295,21 @@ std::string ListLogCategories()
return ret; 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 * 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 * suppress printing of the timestamp when multiple calls are made that don't

11
src/util.h

@ -69,6 +69,12 @@ inline std::string _(const char* psz)
void SetupEnvironment(); void SetupEnvironment();
bool SetupNetworking(); bool SetupNetworking();
struct CLogCategoryActive
{
std::string category;
bool active;
};
namespace BCLog { namespace BCLog {
enum LogFlags : uint32_t { enum LogFlags : uint32_t {
NONE = 0, NONE = 0,
@ -102,9 +108,12 @@ static inline bool LogAcceptCategory(uint32_t category)
return (logCategories.load(std::memory_order_relaxed) & category) != 0; 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(); 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 */ /** Return true if str parses as a log category and set the flags in f */
bool GetLogCategory(uint32_t *f, const std::string *str); bool GetLogCategory(uint32_t *f, const std::string *str);

Loading…
Cancel
Save