From fdcb038e773a168393c3b88946dcd63007685a03 Mon Sep 17 00:00:00 2001 From: instagibbs Date: Fri, 22 Apr 2016 15:10:50 -0700 Subject: [PATCH] Add audit log file --- src/init.cpp | 3 + src/util.cpp | 120 ++++++++++++++++++++++++++++++++------- src/util.h | 22 +++++-- src/wallet/rpcwallet.cpp | 2 + 4 files changed, 120 insertions(+), 27 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index ba1c10e879..4f9f35be2c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1063,6 +1063,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (fPrintToDebugLog) OpenDebugLog(); + if (fPrintToAuditLog) + OpenAuditLog(); + if (!fLogTimestamps) LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime())); LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); diff --git a/src/util.cpp b/src/util.cpp index 56fff86bc5..6207b8f0c4 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -106,14 +106,16 @@ map mapArgs; map > mapMultiArgs; bool fDebug = false; bool fPrintToConsole = false; -bool fPrintToDebugLog = true; bool fDaemon = false; +bool fPrintToDebugLog = true; +bool fPrintToAuditLog = true; bool fServer = false; string strMiscWarning; bool fLogTimestamps = DEFAULT_LOGTIMESTAMPS; bool fLogTimeMicros = DEFAULT_LOGTIMEMICROS; bool fLogIPs = DEFAULT_LOGIPS; std::atomic fReopenDebugLog(false); +volatile bool fReopenAuditLog = false; CTranslationInterface translationInterface; /** Init OpenSSL library multithreading support */ @@ -179,19 +181,23 @@ instance_of_cinit; */ static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT; +static boost::once_flag auditPrintInitFlag = BOOST_ONCE_INIT; /** * We use boost::call_once() to make sure mutexDebugLog and - * vMsgsBeforeOpenLog are initialized in a thread-safe manner. + * vMsgsBeforeOpenDebugLog are initialized in a thread-safe manner. * - * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog + * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenDebugLog * 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 = NULL; +static FILE* fileout_debug = NULL; +static FILE* fileout_audit = NULL; static boost::mutex* mutexDebugLog = NULL; -static list *vMsgsBeforeOpenLog; +static boost::mutex* mutexAuditLog = NULL; +static list *vMsgsBeforeOpenDebugLog; +static list *vMsgsBeforeOpenAuditLog; static int FileWriteStr(const std::string &str, FILE *fp) { @@ -202,7 +208,14 @@ static void DebugPrintInit() { assert(mutexDebugLog == NULL); mutexDebugLog = new boost::mutex(); - vMsgsBeforeOpenLog = new list; + vMsgsBeforeOpenDebugLog = new list; +} + +static void AuditPrintInit() +{ + assert(mutexAuditLog == NULL); + mutexAuditLog = new boost::mutex(); + vMsgsBeforeOpenAuditLog = new list; } void OpenDebugLog() @@ -210,22 +223,44 @@ void OpenDebugLog() boost::call_once(&DebugPrintInit, debugPrintInitFlag); boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); - assert(fileout == NULL); - assert(vMsgsBeforeOpenLog); + assert(fileout_debug == NULL); + assert(vMsgsBeforeOpenDebugLog); boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; - fileout = fopen(pathDebug.string().c_str(), "a"); - if (fileout) setbuf(fileout, NULL); // unbuffered + fileout_debug = fopen(pathDebug.string().c_str(), "a"); + if (fileout_debug) setbuf(fileout_debug, NULL); // unbuffered // dump buffered messages from before we opened the log - while (!vMsgsBeforeOpenLog->empty()) { - FileWriteStr(vMsgsBeforeOpenLog->front(), fileout); - vMsgsBeforeOpenLog->pop_front(); + while (!vMsgsBeforeOpenDebugLog->empty()) { + FileWriteStr(vMsgsBeforeOpenDebugLog->front(), fileout_debug); + vMsgsBeforeOpenDebugLog->pop_front(); } - delete vMsgsBeforeOpenLog; - vMsgsBeforeOpenLog = NULL; + delete vMsgsBeforeOpenDebugLog; + vMsgsBeforeOpenDebugLog = NULL; } +void OpenAuditLog() +{ + boost::call_once(&AuditPrintInit, auditPrintInitFlag); + boost::mutex::scoped_lock scoped_lock(*mutexAuditLog); + + assert(fileout_audit == NULL); + assert(vMsgsBeforeOpenAuditLog); + boost::filesystem::path pathAudit = GetDataDir() / "audit.log"; + fileout_audit = fopen(pathAudit.string().c_str(), "a"); + if (fileout_audit) setbuf(fileout_audit, NULL); // unbuffered + + // dump buffered messages from before we opened the log + while (!vMsgsBeforeOpenAuditLog->empty()) { + FileWriteStr(vMsgsBeforeOpenAuditLog->front(), fileout_audit); + vMsgsBeforeOpenAuditLog->pop_front(); + } + + delete vMsgsBeforeOpenAuditLog; + vMsgsBeforeOpenAuditLog = NULL; +} + + bool LogAcceptCategory(const char* category) { if (category != NULL) @@ -284,7 +319,7 @@ static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine return strStamped; } -int LogPrintStr(const std::string &str) +int DebugLogPrintStr(const std::string &str) { int ret = 0; // Returns total number of characters written static bool fStartedNewLine = true; @@ -303,10 +338,10 @@ int LogPrintStr(const std::string &str) boost::mutex::scoped_lock scoped_lock(*mutexDebugLog); // buffer if we haven't opened the log yet - if (fileout == NULL) { - assert(vMsgsBeforeOpenLog); + if (fileout_debug == NULL) { + assert(vMsgsBeforeOpenDebugLog); ret = strTimestamped.length(); - vMsgsBeforeOpenLog->push_back(strTimestamped); + vMsgsBeforeOpenDebugLog->push_back(strTimestamped); } else { @@ -314,16 +349,57 @@ int LogPrintStr(const std::string &str) if (fReopenDebugLog) { fReopenDebugLog = false; boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; - if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL) - setbuf(fileout, NULL); // unbuffered + if (freopen(pathDebug.string().c_str(),"a",fileout_debug) != NULL) + setbuf(fileout_debug, NULL); // unbuffered } - ret = FileWriteStr(strTimestamped, fileout); + ret = FileWriteStr(strTimestamped, fileout_debug); } } return ret; } +int AuditLogPrintStr(const std::string &str) +{ + int ret = 0; // Returns total number of characters written + static bool fStartedNewLine = true; + + string strTimestamped = LogTimestampStr(str, &fStartedNewLine); + + if (fPrintToConsole) + { + // print to console + ret = fwrite(strTimestamped.data(), 1, strTimestamped.size(), stdout); + fflush(stdout); + } + else if (fPrintToAuditLog) + { + boost::call_once(&AuditPrintInit, auditPrintInitFlag); + boost::mutex::scoped_lock scoped_lock(*mutexAuditLog); + + // buffer if we haven't opened the log yet + if (fileout_audit == NULL) { + assert(vMsgsBeforeOpenAuditLog); + ret = strTimestamped.length(); + vMsgsBeforeOpenAuditLog->push_back(strTimestamped); + } + else + { + // reopen the log file, if requested + if (fReopenAuditLog) { + fReopenAuditLog = false; + boost::filesystem::path pathAudit = GetDataDir() / "audit.log"; + if (freopen(pathAudit.string().c_str(),"a",fileout_audit) != NULL) + setbuf(fileout_audit, NULL); // unbuffered + } + + ret = FileWriteStr(strTimestamped, fileout_audit); + } + } + return ret; +} + + /** Interpret string as boolean, for argument parsing */ static bool InterpretBool(const std::string& strValue) { diff --git a/src/util.h b/src/util.h index ac4b947785..c9cd4068cb 100644 --- a/src/util.h +++ b/src/util.h @@ -46,6 +46,7 @@ extern std::map > mapMultiArgs; extern bool fDebug; extern bool fPrintToConsole; extern bool fPrintToDebugLog; +extern bool fPrintToAuditLog; extern bool fServer; extern std::string strMiscWarning; extern bool fLogTimestamps; @@ -73,24 +74,34 @@ bool SetupNetworking(); /** Return true if log accepts specified category */ bool LogAcceptCategory(const char* category); /** Send a string to the log output */ -int LogPrintStr(const std::string &str); +int DebugLogPrintStr(const std::string &str); +/** Send a string to the audit log output */ +int AuditLogPrintStr(const std::string &str); #define LogPrintf(...) LogPrint(NULL, __VA_ARGS__) +#define AuditLogPrintf(...) AuditLogPrint(NULL, __VA_ARGS__) template static inline int LogPrint(const char* category, const char* fmt, const T1& v1, const Args&... args) { if(!LogAcceptCategory(category)) return 0; \ - return LogPrintStr(tfm::format(fmt, v1, args...)); + return DebugLogPrintStr(tfm::format(fmt, v1, args...)); } template bool error(const char* fmt, const T1& v1, const Args&... args) { - LogPrintStr("ERROR: " + tfm::format(fmt, v1, args...) + "\n"); + DebugLogPrintStr("ERROR: " + tfm::format(fmt, v1, args...) + "\n"); return false; } +template +static inline int AuditLogPrint(const char* category, const char* fmt, const T1& v1, const Args&... args) +{ + if(!LogAcceptCategory(category)) return 0; \ + return AuditLogPrintStr(tfm::format(fmt, v1, args...)); +} + /** * Zero-arg versions of logging and error, these are not covered by * the variadic templates above (and don't take format arguments but @@ -99,11 +110,11 @@ bool error(const char* fmt, const T1& v1, const Args&... args) static inline int LogPrint(const char* category, const char* s) { if(!LogAcceptCategory(category)) return 0; - return LogPrintStr(s); + return DebugLogPrintStr(s); } static inline bool error(const char* s) { - LogPrintStr(std::string("ERROR: ") + s + "\n"); + DebugLogPrintStr(std::string("ERROR: ") + s + "\n"); return false; } @@ -128,6 +139,7 @@ void ReadConfigFile(std::map& mapSettingsRet, std::map boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true); #endif void OpenDebugLog(); +void OpenAuditLog(); void ShrinkDebugFile(); void runCommand(const std::string& strCommand); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d0b09c21de..7c17840d9c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -442,6 +442,8 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp) SendMoney(address.Get(), nAmount, fSubtractFeeFromAmount, confidentiality_pubkey, wtx); + AuditLogPrintf("%s : sendtoaddress %s %d", *userInstance.get(), wtx.GetHash().GetHex(), nAmount); + return wtx.GetHash().GetHex(); }