diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | doc/tor.md | 18 | ||||
-rw-r--r-- | src/bench/bench_bitcoin.cpp | 1 | ||||
-rw-r--r-- | src/httpserver.cpp | 4 | ||||
-rw-r--r-- | src/httpserver.h | 2 | ||||
-rw-r--r-- | src/init.cpp | 36 | ||||
-rw-r--r-- | src/interfaces/node.cpp | 2 | ||||
-rw-r--r-- | src/logging.cpp | 213 | ||||
-rw-r--r-- | src/logging.h | 85 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 37 | ||||
-rw-r--r-- | src/test/test_bitcoin.cpp | 1 | ||||
-rw-r--r-- | src/util.h | 2 |
12 files changed, 212 insertions, 191 deletions
diff --git a/configure.ac b/configure.ac index b68fd8fc58..ce9e683eda 100644 --- a/configure.ac +++ b/configure.ac @@ -84,7 +84,7 @@ AC_PATH_TOOL(STRIP, strip) AC_PATH_TOOL(GCOV, gcov) AC_PATH_PROG(LCOV, lcov) dnl Python 3.x is supported from 3.4 on (see https://github.com/bitcoin/bitcoin/issues/7893) -AC_PATH_PROGS([PYTHON], [python3.6 python3.5 python3.4 python3 python2.7 python2 python]) +AC_PATH_PROGS([PYTHON], [python3.7 python3.6 python3.5 python3.4 python3 python]) AC_PATH_PROG(GENHTML, genhtml) AC_PATH_PROG([GIT], [git]) AC_PATH_PROG(CCACHE,ccache) diff --git a/doc/tor.md b/doc/tor.md index 931c83abdd..f0f98b7d12 100644 --- a/doc/tor.md +++ b/doc/tor.md @@ -1,5 +1,4 @@ -TOR SUPPORT IN BITCOIN -====================== +# TOR SUPPORT IN BITCOIN It is possible to run Bitcoin as a Tor hidden service, and connect to such services. @@ -7,8 +6,7 @@ The following directions assume you have a Tor proxy running on port 9050. Many configure Tor. -1. Run bitcoin behind a Tor proxy ---------------------------------- +## 1. Run bitcoin behind a Tor proxy The first step is running Bitcoin behind a Tor proxy. This will already make all outgoing connections be anonymized, but more is possible. @@ -34,12 +32,12 @@ In a typical situation, this suffices to run behind a Tor proxy: ./bitcoind -proxy=127.0.0.1:9050 -2. Run a bitcoin hidden server ------------------------------- +## 2. Run a bitcoin hidden server If you configure your Tor system accordingly, it is possible to make your node also reachable from the Tor network. Add these lines to your /etc/tor/torrc (or equivalent -config file): +config file): *Needed for Tor version 0.2.7.0 and older versions of Tor only. For newer +versions of Tor see [Section 3](#3-automatically-listen-on-tor).* HiddenServiceDir /var/lib/tor/bitcoin-service/ HiddenServicePort 8333 127.0.0.1:8333 @@ -88,8 +86,7 @@ for normal IPv4/IPv6 communication, use: ./bitcoind -onion=127.0.0.1:9050 -externalip=57qr3yd1nyntf5k.onion -discover -3. Automatically listen on Tor --------------------------------- +## 3. Automatically listen on Tor Starting with Tor version 0.2.7.1 it is possible, through Tor's control socket API, to create and destroy 'ephemeral' hidden services programmatically. @@ -115,8 +112,7 @@ which has the appropriate permissions. An alternative authentication method is t of the `-torpassword` flag and a `hash-password` which can be enabled and specified in Tor configuration. -4. Privacy recommendations ---------------------------- +## 4. Privacy recommendations - Do not add anything but bitcoin ports to the hidden service created in section 2. If you run a web service too, create a new hidden service for that. diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index 1d87883522..c1f3339830 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -46,7 +46,6 @@ main(int argc, char** argv) RandomInit(); ECC_Start(); SetupEnvironment(); - fPrintToDebugLog = false; // don't want to write to debug.log file int64_t evaluations = gArgs.GetArg("-evals", DEFAULT_BENCH_EVALUATIONS); std::string regex_filter = gArgs.GetArg("-filter", DEFAULT_BENCH_FILTER); diff --git a/src/httpserver.cpp b/src/httpserver.cpp index b8b338dfbc..bd08b04c0f 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -364,8 +364,8 @@ bool InitHTTPServer() // 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; + if (!UpdateHTTPServerLogging(g_logger->WillLogCategory(BCLog::LIBEVENT))) { + g_logger->DisableCategory(BCLog::LIBEVENT); } #ifdef WIN32 diff --git a/src/httpserver.h b/src/httpserver.h index f17be65962..8132c887b5 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -32,7 +32,7 @@ void InterruptHTTPServer(); /** Stop HTTP server */ void StopHTTPServer(); -/** Change logging level for libevent. Removes BCLog::LIBEVENT from logCategories if +/** Change logging level for libevent. Removes BCLog::LIBEVENT from log categories if * libevent doesn't support debug logging.*/ bool UpdateHTTPServerLogging(bool enable); diff --git a/src/init.cpp b/src/init.cpp index 99dab605ac..6423d87026 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -305,7 +305,7 @@ static void HandleSIGTERM(int) static void HandleSIGHUP(int) { - fReopenDebugLog = true; + g_logger->m_reopen_file = true; } #ifndef WIN32 @@ -826,15 +826,18 @@ static std::string ResolveErrMsg(const char * const optname, const std::string& */ void InitLogging() { + g_logger->m_print_to_file = !gArgs.IsArgNegated("-debuglogfile"); + g_logger->m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); + // Add newlines to the logfile to distinguish this execution from the last // one; called before console logging is set up, so this is only sent to // debug.log. LogPrintf("\n\n\n\n\n"); - fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false)); - fPrintToDebugLog = !gArgs.IsArgNegated("-debuglogfile"); - fLogTimestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); - fLogTimeMicros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); + g_logger->m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false)); + g_logger->m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); + g_logger->m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); + fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS); std::string version_string = FormatFullVersion(); @@ -962,24 +965,18 @@ bool AppInitParameterInteraction() if (std::none_of(categories.begin(), categories.end(), [](std::string cat){return cat == "0" || cat == "none";})) { for (const auto& cat : categories) { - uint32_t flag = 0; - if (!GetLogCategory(&flag, &cat)) { + if (!g_logger->EnableCategory(cat)) { InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat)); - continue; } - logCategories |= flag; } } } // Now remove the logging categories which were explicitly excluded for (const std::string& cat : gArgs.GetArgs("-debugexclude")) { - uint32_t flag = 0; - if (!GetLogCategory(&flag, &cat)) { + if (!g_logger->DisableCategory(cat)) { InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat)); - continue; } - logCategories &= ~flag; } // Check for -debugnet @@ -1230,18 +1227,19 @@ bool AppInitMain() #ifndef WIN32 CreatePidFile(GetPidFile(), getpid()); #endif - if (fPrintToDebugLog) { - if (gArgs.GetBoolArg("-shrinkdebugfile", logCategories == BCLog::NONE)) { + if (g_logger->m_print_to_file) { + if (gArgs.GetBoolArg("-shrinkdebugfile", g_logger->DefaultShrinkDebugFile())) { // Do this first since it both loads a bunch of debug.log into memory, // and because this needs to happen before any other debug.log printing - ShrinkDebugFile(); + g_logger->ShrinkDebugFile(); } - if (!OpenDebugLog()) { - return InitError(strprintf("Could not open debug log file %s", GetDebugLogPath().string())); + if (!g_logger->OpenDebugLog()) { + return InitError(strprintf("Could not open debug log file %s", + g_logger->m_file_path.string())); } } - if (!fLogTimestamps) + if (!g_logger->m_log_timestamps) LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime())); LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); LogPrintf("Using data directory %s\n", GetDataDir().string()); diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 55786c807f..53d2359caf 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -60,7 +60,7 @@ class NodeImpl : public Node void initLogging() override { InitLogging(); } void initParameterInteraction() override { InitParameterInteraction(); } std::string getWarnings(const std::string& type) override { return GetWarnings(type); } - uint32_t getLogCategories() override { return ::logCategories; } + uint32_t getLogCategories() override { return g_logger->GetCategoryMask(); } bool baseInitialize() override { return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() && diff --git a/src/logging.cpp b/src/logging.cpp index e481582321..10a3b18958 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -4,97 +4,93 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <logging.h> -#include <util.h> -#include <utilstrencodings.h> - -#include <list> -#include <mutex> +#include <utiltime.h> const char * const DEFAULT_DEBUGLOGFILE = "debug.log"; -bool fPrintToConsole = false; -bool fPrintToDebugLog = true; - -bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; -bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; -bool fLogIPs = DEFAULT_LOGIPS; -std::atomic<bool> fReopenDebugLog(false); - -/** Log categories bitfield. */ -std::atomic<uint32_t> logCategories(0); /** - * LogPrintf() has been broken a couple of times now - * by well-meaning people adding mutexes in the most straightforward way. - * It breaks because it may be called by global destructors during shutdown. - * Since the order of destruction of static/global objects is undefined, - * defining a mutex as a global object doesn't work (the mutex gets - * destroyed, and then some later destructor calls OutputDebugStringF, - * maybe indirectly, and you get a core dump at shutdown trying to lock - * the mutex). - */ - -static std::once_flag debugPrintInitFlag; - -/** - * We use std::call_once() to make sure mutexDebugLog and - * vMsgsBeforeOpenLog are initialized in a thread-safe manner. + * NOTE: the logger instances is leaked on exit. This is ugly, but will be + * cleaned up by the OS/libc. Defining a logger as a global object doesn't work + * since the order of destruction of static/global objects is undefined. + * Consider if the logger gets destroyed, and then some later destructor calls + * LogPrintf, maybe indirectly, and you get a core dump at shutdown trying to + * access the logger. When the shutdown sequence is fully audited and tested, + * explicit destruction of these objects can be implemented by changing this + * from a raw pointer to a std::unique_ptr. * - * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog - * are leaked on exit. This is ugly, but will be cleaned up by - * the OS/libc. When the shutdown sequence is fully audited and - * tested, explicit destruction of these objects can be implemented. + * This method of initialization was originally introduced in + * ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c. */ -static FILE* fileout = nullptr; -static std::mutex* mutexDebugLog = nullptr; -static std::list<std::string>* vMsgsBeforeOpenLog; +BCLog::Logger* const g_logger = new BCLog::Logger(); + +bool fLogIPs = DEFAULT_LOGIPS; static int FileWriteStr(const std::string &str, FILE *fp) { return fwrite(str.data(), 1, str.size(), fp); } -static void DebugPrintInit() +bool BCLog::Logger::OpenDebugLog() { - assert(mutexDebugLog == nullptr); - mutexDebugLog = new std::mutex(); - vMsgsBeforeOpenLog = new std::list<std::string>; + std::lock_guard<std::mutex> scoped_lock(m_file_mutex); + + assert(m_fileout == nullptr); + assert(!m_file_path.empty()); + + m_fileout = fsbridge::fopen(m_file_path, "a"); + if (!m_fileout) { + return false; + } + + setbuf(m_fileout, nullptr); // unbuffered + // dump buffered messages from before we opened the log + while (!m_msgs_before_open.empty()) { + FileWriteStr(m_msgs_before_open.front(), m_fileout); + m_msgs_before_open.pop_front(); + } + + return true; } -fs::path GetDebugLogPath() +void BCLog::Logger::EnableCategory(BCLog::LogFlags flag) { - fs::path logfile(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); - return AbsPathForConfigVal(logfile); + m_categories |= flag; } -bool OpenDebugLog() +bool BCLog::Logger::EnableCategory(const std::string& str) { - std::call_once(debugPrintInitFlag, &DebugPrintInit); - std::lock_guard<std::mutex> scoped_lock(*mutexDebugLog); + BCLog::LogFlags flag; + if (!GetLogCategory(flag, str)) return false; + EnableCategory(flag); + return true; +} - assert(fileout == nullptr); - assert(vMsgsBeforeOpenLog); - fs::path pathDebug = GetDebugLogPath(); +void BCLog::Logger::DisableCategory(BCLog::LogFlags flag) +{ + m_categories &= ~flag; +} - fileout = fsbridge::fopen(pathDebug, "a"); - if (!fileout) { - return false; - } +bool BCLog::Logger::DisableCategory(const std::string& str) +{ + BCLog::LogFlags flag; + if (!GetLogCategory(flag, str)) return false; + DisableCategory(flag); + return true; +} - setbuf(fileout, nullptr); // unbuffered - // dump buffered messages from before we opened the log - while (!vMsgsBeforeOpenLog->empty()) { - FileWriteStr(vMsgsBeforeOpenLog->front(), fileout); - vMsgsBeforeOpenLog->pop_front(); - } +bool BCLog::Logger::WillLogCategory(BCLog::LogFlags category) const +{ + return (m_categories.load(std::memory_order_relaxed) & category) != 0; +} - delete vMsgsBeforeOpenLog; - vMsgsBeforeOpenLog = nullptr; - return true; +bool BCLog::Logger::DefaultShrinkDebugFile() const +{ + return m_categories == BCLog::NONE; } struct CLogCategoryDesc { - uint32_t flag; + BCLog::LogFlags flag; std::string category; }; @@ -127,19 +123,17 @@ const CLogCategoryDesc LogCategories[] = {BCLog::ALL, "all"}, }; -bool GetLogCategory(uint32_t *f, const std::string *str) +bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str) { - if (f && str) { - if (*str == "") { - *f = BCLog::ALL; + if (str == "") { + flag = BCLog::ALL; + return true; + } + for (const CLogCategoryDesc& category_desc : LogCategories) { + if (category_desc.category == str) { + flag = category_desc.flag; return true; } - for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) { - if (LogCategories[i].category == *str) { - *f = LogCategories[i].flag; - return true; - } - } } return false; } @@ -148,11 +142,11 @@ std::string ListLogCategories() { std::string ret; int outcount = 0; - for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) { + for (const CLogCategoryDesc& category_desc : LogCategories) { // Omit the special cases. - if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) { + if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) { if (outcount != 0) ret += ", "; - ret += LogCategories[i].category; + ret += category_desc.category; outcount++; } } @@ -162,34 +156,29 @@ std::string ListLogCategories() std::vector<CLogCategoryActive> ListActiveLogCategories() { std::vector<CLogCategoryActive> ret; - for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) { + for (const CLogCategoryDesc& category_desc : LogCategories) { // Omit the special cases. - if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) { + if (category_desc.flag != BCLog::NONE && category_desc.flag != BCLog::ALL) { CLogCategoryActive catActive; - catActive.category = LogCategories[i].category; - catActive.active = LogAcceptCategory(LogCategories[i].flag); + catActive.category = category_desc.category; + catActive.active = LogAcceptCategory(category_desc.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 - * end in a newline. Initialize it to true, and hold it, in the calling context. - */ -static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fStartedNewLine) +std::string BCLog::Logger::LogTimestampStr(const std::string &str) { std::string strStamped; - if (!fLogTimestamps) + if (!m_log_timestamps) return str; - if (*fStartedNewLine) { + if (m_started_new_line) { int64_t nTimeMicros = GetTimeMicros(); strStamped = FormatISO8601DateTime(nTimeMicros/1000000); - if (fLogTimeMicros) { + if (m_log_time_micros) { strStamped.pop_back(); strStamped += strprintf(".%06dZ", nTimeMicros%1000000); } @@ -202,63 +191,61 @@ static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fSt strStamped = str; if (!str.empty() && str[str.size()-1] == '\n') - *fStartedNewLine = true; + m_started_new_line = true; else - *fStartedNewLine = false; + m_started_new_line = false; return strStamped; } -int LogPrintStr(const std::string &str) +int BCLog::Logger::LogPrintStr(const std::string &str) { int ret = 0; // Returns total number of characters written - static std::atomic_bool fStartedNewLine(true); - std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine); + std::string strTimestamped = LogTimestampStr(str); - if (fPrintToConsole) { + if (m_print_to_console) { // print to console ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout); fflush(stdout); } - if (fPrintToDebugLog) { - std::call_once(debugPrintInitFlag, &DebugPrintInit); - std::lock_guard<std::mutex> scoped_lock(*mutexDebugLog); + if (m_print_to_file) { + std::lock_guard<std::mutex> scoped_lock(m_file_mutex); // buffer if we haven't opened the log yet - if (fileout == nullptr) { - assert(vMsgsBeforeOpenLog); + if (m_fileout == nullptr) { ret = strTimestamped.length(); - vMsgsBeforeOpenLog->push_back(strTimestamped); + m_msgs_before_open.push_back(strTimestamped); } else { // reopen the log file, if requested - if (fReopenDebugLog) { - fReopenDebugLog = false; - fs::path pathDebug = GetDebugLogPath(); - if (fsbridge::freopen(pathDebug,"a",fileout) != nullptr) - setbuf(fileout, nullptr); // unbuffered + if (m_reopen_file) { + m_reopen_file = false; + if (fsbridge::freopen(m_file_path,"a",m_fileout) != nullptr) + setbuf(m_fileout, nullptr); // unbuffered } - ret = FileWriteStr(strTimestamped, fileout); + ret = FileWriteStr(strTimestamped, m_fileout); } } return ret; } -void ShrinkDebugFile() +void BCLog::Logger::ShrinkDebugFile() { // Amount of debug.log to save at end when shrinking (must fit in memory) constexpr size_t RECENT_DEBUG_HISTORY_SIZE = 10 * 1000000; + + assert(!m_file_path.empty()); + // Scroll debug.log if it's getting too big - fs::path pathLog = GetDebugLogPath(); - FILE* file = fsbridge::fopen(pathLog, "r"); + FILE* file = fsbridge::fopen(m_file_path, "r"); // Special files (e.g. device nodes) may not have a size. size_t log_size = 0; try { - log_size = fs::file_size(pathLog); + log_size = fs::file_size(m_file_path); } catch (boost::filesystem::filesystem_error &) {} // If debug.log file is more than 10% bigger the RECENT_DEBUG_HISTORY_SIZE @@ -271,7 +258,7 @@ void ShrinkDebugFile() int nBytes = fread(vch.data(), 1, vch.size(), file); fclose(file); - file = fsbridge::fopen(pathLog, "w"); + file = fsbridge::fopen(m_file_path, "w"); if (file) { fwrite(vch.data(), 1, nBytes, file); diff --git a/src/logging.h b/src/logging.h index 4053f75acf..1f2be6016a 100644 --- a/src/logging.h +++ b/src/logging.h @@ -11,6 +11,8 @@ #include <atomic> #include <cstdint> +#include <list> +#include <mutex> #include <string> #include <vector> @@ -19,15 +21,7 @@ static const bool DEFAULT_LOGIPS = false; static const bool DEFAULT_LOGTIMESTAMPS = true; extern const char * const DEFAULT_DEBUGLOGFILE; -extern bool fPrintToConsole; -extern bool fPrintToDebugLog; - -extern bool fLogTimestamps; -extern bool fLogTimeMicros; extern bool fLogIPs; -extern std::atomic<bool> fReopenDebugLog; - -extern std::atomic<uint32_t> logCategories; struct CLogCategoryActive { @@ -61,11 +55,65 @@ namespace BCLog { LEVELDB = (1 << 20), ALL = ~(uint32_t)0, }; -} + + class Logger + { + private: + FILE* m_fileout = nullptr; + std::mutex m_file_mutex; + std::list<std::string> m_msgs_before_open; + + /** + * m_started_new_line is a state variable that will suppress printing of + * the timestamp when multiple calls are made that don't end in a + * newline. + */ + std::atomic_bool m_started_new_line{true}; + + /** Log categories bitfield. */ + std::atomic<uint32_t> m_categories{0}; + + std::string LogTimestampStr(const std::string& str); + + public: + bool m_print_to_console = false; + bool m_print_to_file = false; + + bool m_log_timestamps = DEFAULT_LOGTIMESTAMPS; + bool m_log_time_micros = DEFAULT_LOGTIMEMICROS; + + fs::path m_file_path; + std::atomic<bool> m_reopen_file{false}; + + /** Send a string to the log output */ + int LogPrintStr(const std::string &str); + + /** Returns whether logs will be written to any output */ + bool Enabled() const { return m_print_to_console || m_print_to_file; } + + bool OpenDebugLog(); + void ShrinkDebugFile(); + + uint32_t GetCategoryMask() const { return m_categories.load(); } + + void EnableCategory(LogFlags flag); + bool EnableCategory(const std::string& str); + void DisableCategory(LogFlags flag); + bool DisableCategory(const std::string& str); + + bool WillLogCategory(LogFlags category) const; + + bool DefaultShrinkDebugFile() const; + }; + +} // namespace BCLog + +extern BCLog::Logger* const g_logger; + /** Return true if log accepts specified category */ -static inline bool LogAcceptCategory(uint32_t category) +static inline bool LogAcceptCategory(BCLog::LogFlags category) { - return (logCategories.load(std::memory_order_relaxed) & category) != 0; + return g_logger->WillLogCategory(category); } /** Returns a string with the log categories. */ @@ -74,11 +122,8 @@ 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 */ -bool GetLogCategory(uint32_t *f, const std::string *str); - -/** Send a string to the log output */ -int LogPrintStr(const std::string &str); +/** Return true if str parses as a log category and set the flag */ +bool GetLogCategory(BCLog::LogFlags& flag, const std::string& str); /** Get format string from VA_ARGS for error reporting */ template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; } @@ -99,7 +144,7 @@ template<typename T, typename... Args> static inline void MarkUsed(const T& t, c #define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0) #else #define LogPrintf(...) do { \ - if (fPrintToConsole || fPrintToDebugLog) { \ + if (g_logger->Enabled()) { \ std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ try { \ _log_msg_ = tfm::format(__VA_ARGS__); \ @@ -107,7 +152,7 @@ template<typename T, typename... Args> static inline void MarkUsed(const T& t, c /* Original format string will have newline so don't add one here */ \ _log_msg_ = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(__VA_ARGS__); \ } \ - LogPrintStr(_log_msg_); \ + g_logger->LogPrintStr(_log_msg_); \ } \ } while(0) @@ -118,8 +163,4 @@ template<typename T, typename... Args> static inline void MarkUsed(const T& t, c } while(0) #endif -fs::path GetDebugLogPath(); -bool OpenDebugLog(); -void ShrinkDebugFile(); - #endif // BITCOIN_LOGGING_H diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 6754407dbd..0c93108bce 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -346,21 +346,22 @@ UniValue getmemoryinfo(const JSONRPCRequest& request) } } -uint32_t getCategoryMask(UniValue cats) { +void EnableOrDisableLogCategories(UniValue cats, bool enable) { 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); + + bool success; + if (enable) { + success = g_logger->EnableCategory(cat); + } else { + success = g_logger->DisableCategory(cat); } - if (flag == BCLog::NONE) { - return 0; + + if (!success) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat); } - mask |= flag; } - return mask; } UniValue logging(const JSONRPCRequest& request) @@ -399,25 +400,25 @@ UniValue logging(const JSONRPCRequest& request) ); } - uint32_t originalLogCategories = logCategories; + uint32_t original_log_categories = g_logger->GetCategoryMask(); if (request.params[0].isArray()) { - logCategories |= getCategoryMask(request.params[0]); + EnableOrDisableLogCategories(request.params[0], true); } - if (request.params[1].isArray()) { - logCategories &= ~getCategoryMask(request.params[1]); + EnableOrDisableLogCategories(request.params[1], false); } + uint32_t updated_log_categories = g_logger->GetCategoryMask(); + uint32_t changed_log_categories = original_log_categories ^ updated_log_categories; // 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) { + if (changed_log_categories & BCLog::LIBEVENT) { + if (!UpdateHTTPServerLogging(g_logger->WillLogCategory(BCLog::LIBEVENT))) { + g_logger->DisableCategory(BCLog::LIBEVENT); + if (changed_log_categories == BCLog::LIBEVENT) { throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when using libevent before v2.1.1."); } } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index e9873f4526..fe816a6f79 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -47,7 +47,6 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName) SetupNetworking(); InitSignatureCache(); InitScriptExecutionCache(); - fPrintToDebugLog = false; // don't want to write to debug.log file fCheckBlockIndex = true; SelectParams(chainName); noui_connect(); diff --git a/src/util.h b/src/util.h index ce94f396af..2da8023285 100644 --- a/src/util.h +++ b/src/util.h @@ -66,7 +66,7 @@ bool SetupNetworking(); template<typename... Args> bool error(const char* fmt, const Args&... args) { - LogPrintStr("ERROR: " + tfm::format(fmt, args...) + "\n"); + LogPrintf("ERROR: %s\n", tfm::format(fmt, args...)); return false; } |