From 4d9950d3bc72d92a0ee9a33ab3b77e097eb77354 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Mon, 10 Apr 2017 10:27:36 -0400 Subject: Set BCLog::LIBEVENT correctly for old libevent versions. --- src/httpserver.cpp | 28 ++++++++++++++++++++-------- src/httpserver.h | 4 ++++ 2 files changed, 24 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 347433eb11..e7df23295d 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -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 threadResult; diff --git a/src/httpserver.h b/src/httpserver.h index b55b253bea..6be9950682 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -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 HTTPRequestHandler; /** Register handler for prefix. -- cgit v1.2.3 From 5255aca3f42e44eb02751299e84e2cf122ed9b49 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Mon, 3 Apr 2017 13:39:11 -0400 Subject: [rpc] Add logging RPC Adds an RPC to get and set currently active logging categories. --- src/rpc/client.cpp | 2 ++ src/rpc/misc.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++- src/util.cpp | 17 ++++++++++++++++- src/util.h | 11 ++++++++++- 4 files changed, 83 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 35bc5d6a82..1f3c4e52ad 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -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" }, diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 24c5eeffe9..d20184771e 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -555,6 +555,59 @@ 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,...] \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: (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]); + } + + + UniValue result(UniValue::VOBJ); + std::vector 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 +634,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) diff --git a/src/util.cpp b/src/util.cpp index 5473799289..e859c8a1a4 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -118,7 +118,7 @@ bool fLogIPs = DEFAULT_LOGIPS; std::atomic fReopenDebugLog(false); CTranslationInterface translationInterface; -/** Log categories bitfield. Leveldb/libevent need special handling if their flags are changed at runtime. */ +/** Log categories bitfield. libevent needs special handling if their flags are changed at runtime. */ std::atomic logCategories(0); /** Init OpenSSL library multithreading support */ @@ -295,6 +295,21 @@ std::string ListLogCategories() return ret; } +std::vector ListActiveLogCategories() +{ + std::vector 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 diff --git a/src/util.h b/src/util.h index 7998449fee..ed28070a3f 100644 --- a/src/util.h +++ b/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 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); -- cgit v1.2.3 From 7fd50c3b70397c0dc39093a7a4ddbf9b36a615cf Mon Sep 17 00:00:00 2001 From: John Newbery Date: Mon, 10 Apr 2017 10:34:23 -0400 Subject: allow libevent logging to be updated during runtime --- src/Makefile.test.include | 2 +- src/rpc/misc.cpp | 15 +++++++++++++++ src/util.cpp | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/Makefile.test.include b/src/Makefile.test.include index fe0ed59fe2..d08c8bde5b 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -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) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index d20184771e..7b8aa572d7 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -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" @@ -598,6 +599,20 @@ UniValue logging(const JSONRPCRequest& request) 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 vLogCatActive = ListActiveLogCategories(); diff --git a/src/util.cpp b/src/util.cpp index e859c8a1a4..0dc203cba5 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -118,7 +118,7 @@ bool fLogIPs = DEFAULT_LOGIPS; std::atomic fReopenDebugLog(false); CTranslationInterface translationInterface; -/** Log categories bitfield. libevent needs special handling if their flags are changed at runtime. */ +/** Log categories bitfield. */ std::atomic logCategories(0); /** Init OpenSSL library multithreading support */ -- cgit v1.2.3