forked from dashpay/dash
-
Notifications
You must be signed in to change notification settings - Fork 717
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MOVEONLY: Move logging code from util.{h,cpp} to new files.
backports bitcoin/bitcoin@b77b6e2
- Loading branch information
1 parent
0c8950a
commit 81ddbf4
Showing
6 changed files
with
386 additions
and
331 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <list> | ||
#include <mutex> | ||
|
||
#include <boost/filesystem/fstream.hpp> | ||
|
||
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<bool> fReopenDebugLog(false); | ||
|
||
/** Log categories bitfield. Leveldb/libevent need special handling if their flags are changed at runtime. */ | ||
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 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<std::string> *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<std::string>; | ||
} | ||
|
||
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<CLogCategoryActive> ListActiveLogCategories() | ||
{ | ||
std::vector<CLogCategoryActive> 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<char> 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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <atomic> | ||
#include <vector> | ||
|
||
#include <boost/filesystem.hpp> | ||
|
||
extern bool fPrintToConsole; | ||
extern bool fPrintToDebugLog; | ||
|
||
extern bool fLogTimestamps; | ||
extern bool fLogIPs; | ||
extern std::atomic<bool> fReopenDebugLog; | ||
|
||
extern std::atomic<uint32_t> 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<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); | ||
|
||
/** Get format string from VA_ARGS for error reporting */ | ||
template<typename... Args> 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 |
Oops, something went wrong.