Changeset View
Changeset View
Standalone View
Standalone View
src/logging.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Copyright (c) 2017-2018 The Bitcoin developers | // Copyright (c) 2017-2018 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "logging.h" | #include "logging.h" | ||||
#include "util.h" | #include "util.h" | ||||
#include "utilstrencodings.h" | #include "utilstrencodings.h" | ||||
#include "utiltime.h" | #include "utiltime.h" | ||||
#include <boost/thread/mutex.hpp> | #include <boost/thread/mutex.hpp> | ||||
#include <boost/thread/once.hpp> | #include <boost/thread/once.hpp> | ||||
bool fPrintToConsole = false; | |||||
bool fPrintToDebugLog = true; | |||||
bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; | |||||
bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; | |||||
bool fLogIPs = DEFAULT_LOGIPS; | bool fLogIPs = DEFAULT_LOGIPS; | ||||
std::atomic<bool> fReopenDebugLog(false); | |||||
/** | |||||
* NOTE: the logger instance 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 &GetLogger() { | |||||
static BCLog::Logger *const logger = new BCLog::Logger(); | |||||
return *logger; | |||||
} | |||||
/** | /** | ||||
* Log categories bitfield. Leveldb/libevent need special handling if their | * Log categories bitfield. Leveldb/libevent need special handling if their | ||||
* flags are changed at runtime. | * flags are changed at runtime. | ||||
*/ | */ | ||||
std::atomic<uint32_t> logCategories(0); | std::atomic<uint32_t> logCategories(0); | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | for (unsigned int i = 0; i < ARRAYLEN(LogCategories); i++) { | ||||
if (outcount != 0) ret += ", "; | if (outcount != 0) ret += ", "; | ||||
ret += LogCategories[i].category; | ret += LogCategories[i].category; | ||||
outcount++; | outcount++; | ||||
} | } | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
/** | std::string BCLog::Logger::LogTimestampStr(const std::string &str) { | ||||
* 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 strStamped; | std::string strStamped; | ||||
if (!fLogTimestamps) return str; | if (!fLogTimestamps) return str; | ||||
if (*fStartedNewLine) { | if (fStartedNewLine) { | ||||
int64_t nTimeMicros = GetLogTimeMicros(); | int64_t nTimeMicros = GetLogTimeMicros(); | ||||
strStamped = | strStamped = | ||||
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros / 1000000); | DateTimeStrFormat("%Y-%m-%d %H:%M:%S", nTimeMicros / 1000000); | ||||
if (fLogTimeMicros) | if (fLogTimeMicros) | ||||
strStamped += strprintf(".%06d", nTimeMicros % 1000000); | strStamped += strprintf(".%06d", nTimeMicros % 1000000); | ||||
strStamped += ' ' + str; | strStamped += ' ' + str; | ||||
} else | } else | ||||
strStamped = str; | strStamped = str; | ||||
if (!str.empty() && str[str.size() - 1] == '\n') | if (!str.empty() && str[str.size() - 1] == '\n') | ||||
*fStartedNewLine = true; | fStartedNewLine = true; | ||||
else | else | ||||
*fStartedNewLine = false; | fStartedNewLine = false; | ||||
return strStamped; | return strStamped; | ||||
} | } | ||||
int LogPrintStr(const std::string &str) { | int BCLog::Logger::LogPrintStr(const std::string &str) { | ||||
// Returns total number of characters written. | // Returns total number of characters written. | ||||
int ret = 0; | int ret = 0; | ||||
static std::atomic_bool fStartedNewLine(true); | |||||
std::string strTimestamped = LogTimestampStr(str, &fStartedNewLine); | std::string strTimestamped = LogTimestampStr(str); | ||||
if (fPrintToConsole) { | if (fPrintToConsole) { | ||||
// Print to console. | // Print to console. | ||||
ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout); | ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout); | ||||
fflush(stdout); | fflush(stdout); | ||||
} else if (fPrintToDebugLog) { | } else if (fPrintToDebugLog) { | ||||
boost::call_once(&DebugPrintInit, debugPrintInitFlag); | boost::call_once(&DebugPrintInit, debugPrintInitFlag); | ||||
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); | boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); | ||||
▲ Show 20 Lines • Show All 47 Lines • Show Last 20 Lines |