Skip to content

Commit 350b224

Browse files
committed
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
2 parents b44adf9 + 7fd50c3 commit 350b224

File tree

7 files changed

+123
-12
lines changed

7 files changed

+123
-12
lines changed

src/Makefile.test.include

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ endif
9797
test_test_bitcoin_SOURCES = $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES)
9898
test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) -I$(builddir)/test/ $(TESTDEFS) $(EVENT_CFLAGS)
9999
test_test_bitcoin_LDADD = $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
100-
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS)
100+
$(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS)
101101
test_test_bitcoin_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
102102
if ENABLE_WALLET
103103
test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET)

src/httpserver.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -384,15 +384,13 @@ bool InitHTTPServer()
384384

385385
// Redirect libevent's logging to our own log
386386
event_set_log_callback(&libevent_log_cb);
387-
#if LIBEVENT_VERSION_NUMBER >= 0x02010100
388-
// If -debug=libevent, set full libevent debugging.
389-
// Otherwise, disable all libevent debugging.
390-
if (LogAcceptCategory(BCLog::LIBEVENT)) {
391-
event_enable_debug_logging(EVENT_DBG_ALL);
392-
} else {
393-
event_enable_debug_logging(EVENT_DBG_NONE);
387+
// Update libevent's log handling. Returns false if our version of
388+
// libevent doesn't support debug logging, in which case we should
389+
// clear the BCLog::LIBEVENT flag.
390+
if (!UpdateHTTPServerLogging(logCategories & BCLog::LIBEVENT)) {
391+
logCategories &= ~BCLog::LIBEVENT;
394392
}
395-
#endif
393+
396394
#ifdef WIN32
397395
evthread_use_windows_threads();
398396
#else
@@ -435,6 +433,20 @@ bool InitHTTPServer()
435433
return true;
436434
}
437435

436+
bool UpdateHTTPServerLogging(bool enable) {
437+
#if LIBEVENT_VERSION_NUMBER >= 0x02010100
438+
if (enable) {
439+
event_enable_debug_logging(EVENT_DBG_ALL);
440+
} else {
441+
event_enable_debug_logging(EVENT_DBG_NONE);
442+
}
443+
return true;
444+
#else
445+
// Can't update libevent logging if version < 02010100
446+
return false;
447+
#endif
448+
}
449+
438450
std::thread threadHTTP;
439451
std::future<bool> threadResult;
440452

src/httpserver.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ void InterruptHTTPServer();
3232
/** Stop HTTP server */
3333
void StopHTTPServer();
3434

35+
/** Change logging level for libevent. Removes BCLog::LIBEVENT from logCategories if
36+
* libevent doesn't support debug logging.*/
37+
bool UpdateHTTPServerLogging(bool enable);
38+
3539
/** Handler for requests to a certain HTTP path */
3640
typedef std::function<bool(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
3741
/** Register handler for prefix.

src/rpc/client.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
113113
{ "getmempoolancestors", 1, "verbose" },
114114
{ "getmempooldescendants", 1, "verbose" },
115115
{ "bumpfee", 1, "options" },
116+
{ "logging", 0, "include" },
117+
{ "logging", 1, "exclude" },
116118
// Echo with conversion (For testing only)
117119
{ "echojson", 0, "arg0" },
118120
{ "echojson", 1, "arg1" },

src/rpc/misc.cpp

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "clientversion.h"
88
#include "init.h"
99
#include "validation.h"
10+
#include "httpserver.h"
1011
#include "net.h"
1112
#include "netbase.h"
1213
#include "rpc/blockchain.h"
@@ -555,6 +556,73 @@ UniValue getmemoryinfo(const JSONRPCRequest& request)
555556
}
556557
}
557558

559+
uint32_t getCategoryMask(UniValue cats) {
560+
cats = cats.get_array();
561+
uint32_t mask = 0;
562+
for (unsigned int i = 0; i < cats.size(); ++i) {
563+
uint32_t flag = 0;
564+
std::string cat = cats[i].get_str();
565+
if (!GetLogCategory(&flag, &cat)) {
566+
throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat);
567+
}
568+
mask |= flag;
569+
}
570+
return mask;
571+
}
572+
573+
UniValue logging(const JSONRPCRequest& request)
574+
{
575+
if (request.fHelp || request.params.size() > 2) {
576+
throw std::runtime_error(
577+
"logging [include,...] <exclude>\n"
578+
"Gets and sets the logging configuration.\n"
579+
"When called without an argument, returns the list of categories that are currently being debug logged.\n"
580+
"When called with arguments, adds or removes categories from debug logging.\n"
581+
"The valid logging categories are: " + ListLogCategories() + "\n"
582+
"libevent logging is configured on startup and cannot be modified by this RPC during runtime."
583+
"Arguments:\n"
584+
"1. \"include\" (array of strings) add debug logging for these categories.\n"
585+
"2. \"exclude\" (array of strings) remove debug logging for these categories.\n"
586+
"\nResult: <categories> (string): a list of the logging categories that are active.\n"
587+
"\nExamples:\n"
588+
+ HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
589+
+ HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")
590+
);
591+
}
592+
593+
uint32_t originalLogCategories = logCategories;
594+
if (request.params.size() > 0 && request.params[0].isArray()) {
595+
logCategories |= getCategoryMask(request.params[0]);
596+
}
597+
598+
if (request.params.size() > 1 && request.params[1].isArray()) {
599+
logCategories &= ~getCategoryMask(request.params[1]);
600+
}
601+
602+
// Update libevent logging if BCLog::LIBEVENT has changed.
603+
// If the library version doesn't allow it, UpdateHTTPServerLogging() returns false,
604+
// in which case we should clear the BCLog::LIBEVENT flag.
605+
// Throw an error if the user has explicitly asked to change only the libevent
606+
// flag and it failed.
607+
uint32_t changedLogCategories = originalLogCategories ^ logCategories;
608+
if (changedLogCategories & BCLog::LIBEVENT) {
609+
if (!UpdateHTTPServerLogging(logCategories & BCLog::LIBEVENT)) {
610+
logCategories &= ~BCLog::LIBEVENT;
611+
if (changedLogCategories == BCLog::LIBEVENT) {
612+
throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1.");
613+
}
614+
}
615+
}
616+
617+
UniValue result(UniValue::VOBJ);
618+
std::vector<CLogCategoryActive> vLogCatActive = ListActiveLogCategories();
619+
for (const auto& logCatActive : vLogCatActive) {
620+
result.pushKV(logCatActive.category, logCatActive.active);
621+
}
622+
623+
return result;
624+
}
625+
558626
UniValue echo(const JSONRPCRequest& request)
559627
{
560628
if (request.fHelp)
@@ -581,7 +649,8 @@ static const CRPCCommand commands[] =
581649
/* Not shown in help */
582650
{ "hidden", "setmocktime", &setmocktime, true, {"timestamp"}},
583651
{ "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
584-
{ "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
652+
{ "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}},
653+
{ "hidden", "logging", &logging, true, {"include", "exclude"}},
585654
};
586655

587656
void RegisterMiscRPCCommands(CRPCTable &t)

src/util.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ bool fLogIPs = DEFAULT_LOGIPS;
118118
std::atomic<bool> fReopenDebugLog(false);
119119
CTranslationInterface translationInterface;
120120

121-
/** Log categories bitfield. Leveldb/libevent need special handling if their flags are changed at runtime. */
121+
/** Log categories bitfield. */
122122
std::atomic<uint32_t> logCategories(0);
123123

124124
/** Init OpenSSL library multithreading support */
@@ -295,6 +295,21 @@ std::string ListLogCategories()
295295
return ret;
296296
}
297297

298+
std::vector<CLogCategoryActive> ListActiveLogCategories()
299+
{
300+
std::vector<CLogCategoryActive> ret;
301+
for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) {
302+
// Omit the special cases.
303+
if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) {
304+
CLogCategoryActive catActive;
305+
catActive.category = LogCategories[i].category;
306+
catActive.active = LogAcceptCategory(LogCategories[i].flag);
307+
ret.push_back(catActive);
308+
}
309+
}
310+
return ret;
311+
}
312+
298313
/**
299314
* fStartedNewLine is a state variable held by the calling context that will
300315
* suppress printing of the timestamp when multiple calls are made that don't

src/util.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ inline std::string _(const char* psz)
6969
void SetupEnvironment();
7070
bool SetupNetworking();
7171

72+
struct CLogCategoryActive
73+
{
74+
std::string category;
75+
bool active;
76+
};
77+
7278
namespace BCLog {
7379
enum LogFlags : uint32_t {
7480
NONE = 0,
@@ -102,9 +108,12 @@ static inline bool LogAcceptCategory(uint32_t category)
102108
return (logCategories.load(std::memory_order_relaxed) & category) != 0;
103109
}
104110

105-
/** Returns a string with the supported log categories */
111+
/** Returns a string with the log categories. */
106112
std::string ListLogCategories();
107113

114+
/** Returns a vector of the active log categories. */
115+
std::vector<CLogCategoryActive> ListActiveLogCategories();
116+
108117
/** Return true if str parses as a log category and set the flags in f */
109118
bool GetLogCategory(uint32_t *f, const std::string *str);
110119

0 commit comments

Comments
 (0)