From f55f4fcf05a53fdf618b4c69ddcf4c43b14e84c2 Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Wed, 11 Apr 2018 10:03:21 -0700 Subject: [PATCH] util: Establish global logger object. The object encapsulates logging configuration, and in a later commit, set up routines will also be moved into the class. --- src/bench/bench_bitcoin.cpp | 2 +- src/init.cpp | 15 ++++++------ src/logging.cpp | 37 +++++++++++++++-------------- src/logging.h | 47 +++++++++++++++++++++++++++---------- src/test/test_bitcoin.cpp | 2 +- src/util.h | 2 +- 6 files changed, 66 insertions(+), 39 deletions(-) diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index 1d8788352..f08c099c1 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -46,7 +46,7 @@ main(int argc, char** argv) RandomInit(); ECC_Start(); SetupEnvironment(); - fPrintToDebugLog = false; // don't want to write to debug.log file + g_logger->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/init.cpp b/src/init.cpp index 99dab605a..814fd3944 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->fReopenDebugLog = true; } #ifndef WIN32 @@ -831,10 +831,11 @@ void InitLogging() // 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->fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false)); + g_logger->fPrintToDebugLog = !gArgs.IsArgNegated("-debuglogfile"); + g_logger->fLogTimestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); + g_logger->fLogTimeMicros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); + fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS); std::string version_string = FormatFullVersion(); @@ -1230,7 +1231,7 @@ bool AppInitMain() #ifndef WIN32 CreatePidFile(GetPidFile(), getpid()); #endif - if (fPrintToDebugLog) { + if (g_logger->fPrintToDebugLog) { if (gArgs.GetBoolArg("-shrinkdebugfile", logCategories == BCLog::NONE)) { // 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 @@ -1241,7 +1242,7 @@ bool AppInitMain() } } - if (!fLogTimestamps) + if (!g_logger->fLogTimestamps) 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/logging.cpp b/src/logging.cpp index e48158232..de222d946 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -12,13 +12,22 @@ const char * const DEFAULT_DEBUGLOGFILE = "debug.log"; -bool fPrintToConsole = false; -bool fPrintToDebugLog = true; +/** + * 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. + * + * This method of initialization was originally introduced in + * ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c. + */ +BCLog::Logger* const g_logger = new BCLog::Logger(); -bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; -bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; bool fLogIPs = DEFAULT_LOGIPS; -std::atomic fReopenDebugLog(false); /** Log categories bitfield. */ std::atomic logCategories(0); @@ -174,19 +183,14 @@ std::vector ListActiveLogCategories() 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) return str; - if (*fStartedNewLine) { + if (fStartedNewLine) { int64_t nTimeMicros = GetTimeMicros(); strStamped = FormatISO8601DateTime(nTimeMicros/1000000); if (fLogTimeMicros) { @@ -202,19 +206,18 @@ static std::string LogTimestampStr(const std::string &str, std::atomic_bool *fSt strStamped = str; if (!str.empty() && str[str.size()-1] == '\n') - *fStartedNewLine = true; + fStartedNewLine = true; else - *fStartedNewLine = false; + fStartedNewLine = 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) { // print to console diff --git a/src/logging.h b/src/logging.h index 4053f75ac..1ccf9136f 100644 --- a/src/logging.h +++ b/src/logging.h @@ -19,13 +19,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 fReopenDebugLog; extern std::atomic logCategories; @@ -61,7 +55,39 @@ namespace BCLog { LEVELDB = (1 << 20), ALL = ~(uint32_t)0, }; -} + + class Logger + { + private: + /** + * fStartedNewLine 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 fStartedNewLine{true}; + + std::string LogTimestampStr(const std::string& str); + + public: + bool fPrintToConsole = false; + bool fPrintToDebugLog = true; + + bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; + bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; + + std::atomic fReopenDebugLog{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 fPrintToConsole || fPrintToDebugLog; } + }; + +} // namespace BCLog + +extern BCLog::Logger* const g_logger; + /** Return true if log accepts specified category */ static inline bool LogAcceptCategory(uint32_t category) { @@ -77,9 +103,6 @@ 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; } @@ -99,7 +122,7 @@ template 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 +130,7 @@ template 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) diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index e9873f452..fa59a9ce3 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -47,7 +47,7 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName) SetupNetworking(); InitSignatureCache(); InitScriptExecutionCache(); - fPrintToDebugLog = false; // don't want to write to debug.log file + g_logger->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 ce94f396a..2da802328 100644 --- a/src/util.h +++ b/src/util.h @@ -66,7 +66,7 @@ bool SetupNetworking(); template 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; }