diff --git a/src/logging.h b/src/logging.h --- a/src/logging.h +++ b/src/logging.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -23,6 +24,11 @@ extern bool fLogIPs; extern const char *const DEFAULT_DEBUGLOGFILE; +struct CLogCategoryActive { + std::string category; + bool active; +}; + namespace BCLog { enum LogFlags : uint32_t { @@ -64,7 +70,7 @@ std::atomic_bool m_started_new_line{true}; /** - * Log categories bitfield. Leveldb/libevent need special handling if their + * Log categories bitfield. libevent needs special handling if their * flags are changed at runtime. */ std::atomic m_categories{0}; @@ -110,9 +116,12 @@ return GetLogger().WillLogCategory(category); } -/** 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 flag */ bool GetLogCategory(BCLog::LogFlags &flag, const std::string &str); diff --git a/src/logging.cpp b/src/logging.cpp --- a/src/logging.cpp +++ b/src/logging.cpp @@ -129,6 +129,21 @@ 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; +} + BCLog::Logger::~Logger() { if (m_fileout) { fclose(m_fileout); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -124,6 +124,8 @@ {"getmempoolancestors", 1, "verbose"}, {"getmempooldescendants", 1, "verbose"}, {"disconnectnode", 1, "nodeid"}, + {"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 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -439,6 +440,76 @@ } } +void enableCategoryMask(UniValue cats) { + cats = cats.get_array(); + for (unsigned int i = 0; i < cats.size(); ++i) { + BCLog::LogFlags flag = BCLog::NONE; + std::string cat = cats[i].get_str(); + if (!GetLogCategory(flag, cat)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, + "unknown logging category " + cat); + } + GetLogger().EnableCategory(flag); + } +} + +void disableCategoryMask(UniValue cats) { + cats = cats.get_array(); + for (unsigned int i = 0; i < cats.size(); ++i) { + BCLog::LogFlags flag = BCLog::NONE; + std::string cat = cats[i].get_str(); + if (!GetLogCategory(flag, cat)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, + "unknown logging category " + cat); + } + GetLogger().DisableCategory(flag); + } +} + +UniValue logging(const Config &config, 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.\n" + "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:\n" + " (string): a list of the logging categories that are " + "active.\n" + "\nExamples:\n" + + HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"") + + HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")); + } + + if (request.params.size() > 0 && request.params[0].isArray()) { + enableCategoryMask(request.params[0]); + } + + if (request.params.size() > 1 && request.params[1].isArray()) { + disableCategoryMask(request.params[1]); + } + + UniValue result(UniValue::VOBJ); + std::vector vLogCatActive = ListActiveLogCategories(); + for (const auto &logCatActive : vLogCatActive) { + result.pushKV(logCatActive.category, logCatActive.active); + } + + return result; +} + static UniValue echo(const Config &config, const JSONRPCRequest &request) { if (request.fHelp) { throw std::runtime_error( @@ -482,6 +553,7 @@ { "hidden", "echo", echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, { "hidden", "echojson", echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, { "hidden", "getinfo", getinfo_deprecated, {}}, + { "hidden", "logging", logging, {"include", "exclude"}}, }; // clang-format on