From 5255aca3f42e44eb02751299e84e2cf122ed9b49 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Mon, 3 Apr 2017 13:39:11 -0400 Subject: [PATCH] [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(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 35bc5d6a8..1f3c4e52a 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 24c5eeffe..d20184771 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 547379928..e859c8a1a 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 7998449fe..ed28070a3 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);