diff --git a/CMakeLists.txt b/CMakeLists.txt index da16e2efc937f..0859d6a836485 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -504,6 +504,7 @@ set(UTIL_SOURCES ./src/compat/glibcxx_sanity.cpp ./src/chainparamsbase.cpp ./src/clientversion.cpp + ./src/logging.cpp ./src/random.cpp ./src/rpc/protocol.cpp ./src/sync.cpp diff --git a/src/Makefile.am b/src/Makefile.am index e9fc98fbd10f3..a79501f75f1dd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -130,6 +130,7 @@ BITCOIN_CORE_H = \ keystore.h \ leveldbwrapper.h \ limitedmap.h \ + logging.h \ main.h \ masternode.h \ masternode-payments.h \ @@ -418,6 +419,7 @@ libbitcoin_util_a_SOURCES = \ compat/glibc_sanity.cpp \ compat/glibcxx_sanity.cpp \ compat/strnlen.cpp \ + logging.cpp \ random.cpp \ rpc/protocol.cpp \ support/cleanse.cpp \ diff --git a/src/logging.cpp b/src/logging.cpp new file mode 100644 index 0000000000000..e88dd1da14c14 --- /dev/null +++ b/src/logging.cpp @@ -0,0 +1,260 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 The Bitcoin developers +// Copyright (c) 2015-2020 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chainparamsbase.h" +#include "logging.h" +#include "util.h" +#include "utilstrencodings.h" + +#include +#include + +#include + +const char * const DEFAULT_DEBUGLOGFILE = "debug.log"; +namespace fs = boost::filesystem; + +bool fPrintToConsole = false; +bool fPrintToDebugLog = true; +bool fLogTimestamps = false; +bool fLogIPs = false; +std::atomic fReopenDebugLog(false); + +/** Log categories bitfield. Leveldb/libevent need special handling if their flags are changed at runtime. */ +std::atomic 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 boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT; + +/** + * We use boost::call_once() to make sure these are initialized + * in a thread-safe manner the first time called: + */ +static FILE* fileout = nullptr; +static boost::mutex* mutexDebugLog = nullptr; +static std::list *vMsgsBeforeOpenLog; + +static int FileWriteStr(const std::string &str, FILE *fp) +{ + return fwrite(str.data(), 1, str.size(), fp); +} + +static void DebugPrintInit() +{ + assert(mutexDebugLog == nullptr); + mutexDebugLog = new boost::mutex(); + vMsgsBeforeOpenLog = new std::list; +} + +fs::path GetDebugLogPath() +{ + fs::path logfile(GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); + if (logfile.is_absolute()) { + return logfile; + } else { + return GetDataDir() / logfile; + } +} + +bool OpenDebugLog() +{ + boost::call_once(&DebugPrintInit, debugPrintInitFlag); + boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); + assert(fileout == nullptr); + assert(vMsgsBeforeOpenLog); + + fs::path pathDebug = GetDebugLogPath(); + + fileout = fopen(pathDebug.string().c_str(), "a"); + if (!fileout) return false; + + setbuf(fileout, nullptr); // unbuffered + // dump buffered messages from before we opened the log + while (!vMsgsBeforeOpenLog->empty()) { + FileWriteStr(vMsgsBeforeOpenLog->front(), fileout); + vMsgsBeforeOpenLog->pop_front(); + } + + delete vMsgsBeforeOpenLog; + vMsgsBeforeOpenLog = nullptr; + return true; +} + +struct CLogCategoryDesc +{ + uint32_t flag; + std::string category; +}; + +const CLogCategoryDesc LogCategories[] = { + {BCLog::NONE, "0"}, + {BCLog::NET, "net"}, + {BCLog::TOR, "tor"}, + {BCLog::MEMPOOL, "mempool"}, + {BCLog::HTTP, "http"}, + {BCLog::BENCH, "bench"}, + {BCLog::ZMQ, "zmq"}, + {BCLog::DB, "db"}, + {BCLog::RPC, "rpc"}, + {BCLog::ESTIMATEFEE, "estimatefee"}, + {BCLog::ADDRMAN, "addrman"}, + {BCLog::SELECTCOINS, "selectcoins"}, + {BCLog::REINDEX, "reindex"}, + {BCLog::CMPCTBLOCK, "cmpctblock"}, + {BCLog::RAND, "rand"}, + {BCLog::PRUNE, "prune"}, + {BCLog::PROXY, "proxy"}, + {BCLog::MEMPOOLREJ, "mempoolrej"}, + {BCLog::LIBEVENT, "libevent"}, + {BCLog::COINDB, "coindb"}, + {BCLog::QT, "qt"}, + {BCLog::LEVELDB, "leveldb"}, + {BCLog::STAKING, "staking"}, + {BCLog::MASTERNODE, "masternode"}, + {BCLog::MNBUDGET, "mnbudget"}, + {BCLog::LEGACYZC, "zero"}, + {BCLog::ALL, "1"}, + {BCLog::ALL, "all"}, +}; + +bool GetLogCategory(uint32_t *f, const std::string *str) +{ + if (f && str) { + if (*str == "") { + *f = BCLog::ALL; + return true; + } + for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) { + if (LogCategories[i].category == *str) { + *f = LogCategories[i].flag; + return true; + } + } + } + return false; +} + +std::string ListLogCategories() +{ + std::string ret; + int outcount = 0; + for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) { + // Omit the special cases. + if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) { + if (outcount != 0) ret += ", "; + ret += LogCategories[i].category; + outcount++; + } + } + 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 + * end in a newline. Initialize it to true, and hold it, in the calling context. + */ +static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine) +{ + std::string strStamped; + + if (!fLogTimestamps) + return str; + + if (*fStartedNewLine) + strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()) + ' ' + str; + else + strStamped = str; + + if (!str.empty() && str[str.size()-1] == '\n') + *fStartedNewLine = true; + else + *fStartedNewLine = false; + + return strStamped; +} + +int LogPrintStr(const std::string& str) +{ + int ret = 0; // Returns total number of characters written + static bool fStartedNewLine = true; + if (fPrintToConsole) { + // print to console + ret = fwrite(str.data(), 1, str.size(), stdout); + fflush(stdout); + } else if (fPrintToDebugLog) { + boost::call_once(&DebugPrintInit, debugPrintInitFlag); + boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); + + std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine); + + // buffer if we haven't opened the log yet + if (fileout == NULL) { + assert(vMsgsBeforeOpenLog); + ret = strTimestamped.length(); + vMsgsBeforeOpenLog->push_back(strTimestamped); + + } else { + // reopen the log file, if requested + if (fReopenDebugLog) { + fReopenDebugLog = false; + fs::path pathDebug = GetDebugLogPath(); + if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) + setbuf(fileout, NULL); // unbuffered + } + + ret = FileWriteStr(strTimestamped, fileout); + } + } + + return ret; +} + +void ShrinkDebugFile() +{ + // Scroll debug.log if it's getting too big + fs::path pathLog = GetDebugLogPath(); + FILE* file = fopen(pathLog.string().c_str(), "r"); + if (file && fs::file_size(pathLog) > 10 * 1000000) { + // Restart the file with some of the end + std::vector vch(200000, 0); + fseek(file, -((long)vch.size()), SEEK_END); + int nBytes = fread(vch.data(), 1, vch.size(), file); + fclose(file); + + file = fopen(pathLog.string().c_str(), "w"); + if (file) { + fwrite(vch.data(), 1, nBytes, file); + fclose(file); + } + } else if (file != NULL) + fclose(file); +} diff --git a/src/logging.h b/src/logging.h new file mode 100644 index 0000000000000..912f84bb0d388 --- /dev/null +++ b/src/logging.h @@ -0,0 +1,114 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 The Bitcoin developers +// Copyright (c) 2015-2020 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +/** + * Server/client environment: argument handling, config file parsing, + * logging, thread wrappers + */ +#ifndef BITCOIN_LOGGING_H +#define BITCOIN_LOGGING_H + +#include "tinyformat.h" + +#include +#include + +#include + +extern bool fPrintToConsole; +extern bool fPrintToDebugLog; + +extern bool fLogTimestamps; +extern bool fLogIPs; +extern std::atomic fReopenDebugLog; + +extern std::atomic logCategories; + +struct CLogCategoryActive +{ + std::string category; + bool active; +}; + +namespace BCLog { + enum LogFlags : uint32_t { + NONE = 0, + NET = (1 << 0), + TOR = (1 << 1), + MEMPOOL = (1 << 2), + HTTP = (1 << 3), + BENCH = (1 << 4), + ZMQ = (1 << 5), + DB = (1 << 6), + RPC = (1 << 7), + ESTIMATEFEE = (1 << 8), + ADDRMAN = (1 << 9), + SELECTCOINS = (1 << 10), + REINDEX = (1 << 11), + CMPCTBLOCK = (1 << 12), + RAND = (1 << 13), + PRUNE = (1 << 14), + PROXY = (1 << 15), + MEMPOOLREJ = (1 << 16), + LIBEVENT = (1 << 17), + COINDB = (1 << 18), + QT = (1 << 19), + LEVELDB = (1 << 20), + STAKING = (1 << 21), + MASTERNODE = (1 << 22), + MNBUDGET = (1 << 23), + LEGACYZC = (1 << 24), + ALL = ~(uint32_t)0, + }; +} + +/** Return true if log accepts specified category */ +static inline bool LogAcceptCategory(uint32_t category) +{ + return (logCategories.load(std::memory_order_relaxed) & category) != 0; +} + +/** Returns a string with the supported 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); + +/** Send a string to the log output */ +int LogPrintStr(const std::string& str); + +/** Get format string from VA_ARGS for error reporting */ +template std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; } + +// Be conservative when using LogPrintf/error or other things which +// unconditionally log to debug.log! It should not be the case that an inbound +// peer can fill up a user's disk with debug.log entries. + +#define LogPrintf(...) do { \ + std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ + try { \ + _log_msg_ = tfm::format(__VA_ARGS__); \ + } catch (tinyformat::format_error &e) { \ + /* Original format string will have newline so don't add one here */ \ + _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(__VA_ARGS__); \ + } \ + LogPrintStr(_log_msg_); \ +} while(0) + +#define LogPrint(category, ...) do { \ + if (LogAcceptCategory((category))) { \ + LogPrintf(__VA_ARGS__); \ + } \ +} while(0) + +boost::filesystem::path GetDebugLogPath(); +bool OpenDebugLog(); +void ShrinkDebugFile(); + +#endif // BITCOIN_LOGGING_H diff --git a/src/util.cpp b/src/util.cpp index 452ef33ca154a..4a81cd1844b4a 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -22,6 +22,8 @@ #include +namespace fs = boost::filesystem; + #ifndef WIN32 // for posix_fallocate @@ -102,21 +104,11 @@ bool fSucessfullyLoaded = false; std::vector obfuScationDenominations; std::string strBudgetMode = ""; -const char * const DEFAULT_DEBUGLOGFILE = "debug.log"; -namespace fs = boost::filesystem; - std::map mapArgs; std::map > mapMultiArgs; -bool fPrintToConsole = false; -bool fPrintToDebugLog = true; + bool fDaemon = false; std::string strMiscWarning; -bool fLogTimestamps = false; -bool fLogIPs = false; -volatile bool fReopenDebugLog = false; - -/** Log categories bitfield. */ -std::atomic logCategories(0); /** Init OpenSSL library multithreading support */ static RecursiveMutex** ppmutexOpenSSL; @@ -168,222 +160,6 @@ class CInit } } instance_of_cinit; -/** - * 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 boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT; -/** - * We use boost::call_once() to make sure mutexDebugLog and - * vMsgsBeforeOpenLog are initialized in a thread-safe manner. - * - * 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. - */ -static FILE* fileout = nullptr; -static boost::mutex* mutexDebugLog = nullptr; - -static std::list *vMsgsBeforeOpenLog; - -static int FileWriteStr(const std::string &str, FILE *fp) -{ - return fwrite(str.data(), 1, str.size(), fp); -} - -static void DebugPrintInit() -{ - assert(mutexDebugLog == nullptr); - mutexDebugLog = new boost::mutex(); - vMsgsBeforeOpenLog = new std::list; -} - -fs::path GetDebugLogPath() -{ - fs::path logfile(GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); - if (logfile.is_absolute()) { - return logfile; - } else { - return GetDataDir() / logfile; - } -} - -bool OpenDebugLog() -{ - boost::call_once(&DebugPrintInit, debugPrintInitFlag); - boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); - assert(fileout == nullptr); - assert(vMsgsBeforeOpenLog); - - boost::filesystem::path pathDebug = GetDebugLogPath(); - - fileout = fopen(pathDebug.string().c_str(), "a"); - if (!fileout) return false; - - setbuf(fileout, nullptr); // unbuffered - // dump buffered messages from before we opened the log - while (!vMsgsBeforeOpenLog->empty()) { - FileWriteStr(vMsgsBeforeOpenLog->front(), fileout); - vMsgsBeforeOpenLog->pop_front(); - } - - delete vMsgsBeforeOpenLog; - vMsgsBeforeOpenLog = nullptr; - return true; -} - -struct CLogCategoryDesc -{ - uint32_t flag; - std::string category; -}; - -const CLogCategoryDesc LogCategories[] = { - {BCLog::NONE, "0"}, - {BCLog::NET, "net"}, - {BCLog::TOR, "tor"}, - {BCLog::MEMPOOL, "mempool"}, - {BCLog::HTTP, "http"}, - {BCLog::BENCH, "bench"}, - {BCLog::ZMQ, "zmq"}, - {BCLog::DB, "db"}, - {BCLog::RPC, "rpc"}, - {BCLog::ESTIMATEFEE, "estimatefee"}, - {BCLog::ADDRMAN, "addrman"}, - {BCLog::SELECTCOINS, "selectcoins"}, - {BCLog::REINDEX, "reindex"}, - {BCLog::CMPCTBLOCK, "cmpctblock"}, - {BCLog::RAND, "rand"}, - {BCLog::PRUNE, "prune"}, - {BCLog::PROXY, "proxy"}, - {BCLog::MEMPOOLREJ, "mempoolrej"}, - {BCLog::LIBEVENT, "libevent"}, - {BCLog::COINDB, "coindb"}, - {BCLog::QT, "qt"}, - {BCLog::LEVELDB, "leveldb"}, - {BCLog::STAKING, "staking"}, - {BCLog::MASTERNODE, "masternode"}, - {BCLog::MNBUDGET, "mnbudget"}, - {BCLog::LEGACYZC, "zero"}, - {BCLog::ALL, "1"}, - {BCLog::ALL, "all"}, -}; - -bool GetLogCategory(uint32_t *f, const std::string *str) -{ - if (f && str) { - if (*str == "") { - *f = BCLog::ALL; - return true; - } - for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) { - if (LogCategories[i].category == *str) { - *f = LogCategories[i].flag; - return true; - } - } - } - return false; -} - -std::string ListLogCategories() -{ - std::string ret; - int outcount = 0; - for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) { - // Omit the special cases. - if (LogCategories[i].flag != BCLog::NONE && LogCategories[i].flag != BCLog::ALL) { - if (outcount != 0) ret += ", "; - ret += LogCategories[i].category; - outcount++; - } - } - 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, bool *fStartedNewLine) -{ - std::string strStamped; - - if (!fLogTimestamps) - return str; - - if (*fStartedNewLine) - strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()) + ' ' + str; - else - strStamped = str; - - if (!str.empty() && str[str.size()-1] == '\n') - *fStartedNewLine = true; - else - *fStartedNewLine = false; - - return strStamped; -} - -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; -} - -int LogPrintStr(const std::string& str) -{ - int ret = 0; // Returns total number of characters written - static bool fStartedNewLine = true; - if (fPrintToConsole) { - // print to console - ret = fwrite(str.data(), 1, str.size(), stdout); - fflush(stdout); - } else if (fPrintToDebugLog) { - boost::call_once(&DebugPrintInit, debugPrintInitFlag); - boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); - - std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine); - - // buffer if we haven't opened the log yet - if (fileout == NULL) { - assert(vMsgsBeforeOpenLog); - ret = strTimestamped.length(); - vMsgsBeforeOpenLog->push_back(strTimestamped); - - } else { - // reopen the log file, if requested - if (fReopenDebugLog) { - fReopenDebugLog = false; - boost::filesystem::path pathDebug = GetDebugLogPath(); - if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) - setbuf(fileout, NULL); // unbuffered - } - - ret = FileWriteStr(strTimestamped, fileout); - } - } - - return ret; -} /** Interpret string as boolean, for argument parsing */ static bool InterpretBool(const std::string& strValue) @@ -765,27 +541,6 @@ void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length) #endif } -void ShrinkDebugFile() -{ - // Scroll debug.log if it's getting too big - boost::filesystem::path pathLog = GetDebugLogPath(); - FILE* file = fopen(pathLog.string().c_str(), "r"); - if (file && boost::filesystem::file_size(pathLog) > 10 * 1000000) { - // Restart the file with some of the end - std::vector vch(200000, 0); - fseek(file, -((long)vch.size()), SEEK_END); - int nBytes = fread(vch.data(), 1, vch.size(), file); - fclose(file); - - file = fopen(pathLog.string().c_str(), "w"); - if (file) { - fwrite(vch.data(), 1, nBytes, file); - fclose(file); - } - } else if (file != NULL) - fclose(file); -} - #ifdef WIN32 boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate) { diff --git a/src/util.h b/src/util.h index e5bb1d30b5cbb..13082b023a89a 100644 --- a/src/util.h +++ b/src/util.h @@ -7,7 +7,7 @@ /** * Server/client environment: argument handling, config file parsing, - * logging, thread wrappers + * thread wrappers */ #ifndef BITCOIN_UTIL_H #define BITCOIN_UTIL_H @@ -16,6 +16,7 @@ #include "config/pivx-config.h" #endif +#include "logging.h" #include "compat.h" #include "tinyformat.h" #include "utiltime.h" @@ -46,92 +47,16 @@ extern int keysLoaded; extern bool fSucessfullyLoaded; extern std::vector obfuScationDenominations; extern std::string strBudgetMode; -extern std::atomic logCategories; + extern std::map mapArgs; extern std::map > mapMultiArgs; -extern bool fPrintToConsole; -extern bool fPrintToDebugLog; + extern std::string strMiscWarning; -extern bool fLogTimestamps; -extern bool fLogIPs; -extern volatile bool fReopenDebugLog; + void SetupEnvironment(); bool SetupNetworking(); -struct CLogCategoryActive -{ - std::string category; - bool active; -}; - -namespace BCLog { - enum LogFlags : uint32_t { - NONE = 0, - NET = (1 << 0), - TOR = (1 << 1), - MEMPOOL = (1 << 2), - HTTP = (1 << 3), - BENCH = (1 << 4), - ZMQ = (1 << 5), - DB = (1 << 6), - RPC = (1 << 7), - ESTIMATEFEE = (1 << 8), - ADDRMAN = (1 << 9), - SELECTCOINS = (1 << 10), - REINDEX = (1 << 11), - CMPCTBLOCK = (1 << 12), - RAND = (1 << 13), - PRUNE = (1 << 14), - PROXY = (1 << 15), - MEMPOOLREJ = (1 << 16), - LIBEVENT = (1 << 17), - COINDB = (1 << 18), - QT = (1 << 19), - LEVELDB = (1 << 20), - STAKING = (1 << 21), - MASTERNODE = (1 << 22), - MNBUDGET = (1 << 23), - LEGACYZC = (1 << 24), - ALL = ~(uint32_t)0, - }; -} - -/** Return true if log accepts specified category */ -static inline bool LogAcceptCategory(uint32_t category) -{ - return (logCategories.load(std::memory_order_relaxed) & category) != 0; -} - -/** 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); -/** Send a string to the log output */ -int LogPrintStr(const std::string& str); - -/** Get format string from VA_ARGS for error reporting */ -template std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; } - -#define LogPrintf(...) do { \ - std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ - try { \ - _log_msg_ = tfm::format(__VA_ARGS__); \ - } catch (tinyformat::format_error &e) { \ - /* Original format string will have newline so don't add one here */ \ - _log_msg_ = "Error \"" + std::string(e.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(__VA_ARGS__); \ - } \ - LogPrintStr(_log_msg_); \ -} while(0) - -#define LogPrint(category, ...) do { \ - if (LogAcceptCategory((category))) { \ - LogPrintf(__VA_ARGS__); \ - } \ -} while(0) - template bool error(const char* fmt, const Args&... args) { @@ -163,9 +88,7 @@ void ReadConfigFile(std::map& mapSettingsRet, std::map boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif boost::filesystem::path GetTempPath(); -boost::filesystem::path GetDebugLogPath(); -bool OpenDebugLog(); -void ShrinkDebugFile(); + void runCommand(std::string strCommand); inline bool IsSwitchChar(char c)