From b839ae0552dd0d649934485daa424042f9fc73a6 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Thu, 12 Sep 2013 15:03:39 -0700 Subject: [PATCH] Refactor Log code, add LogJournal adapter --- Builds/VisualStudio2012/RippleD.vcxproj | 52 +++- .../VisualStudio2012/RippleD.vcxproj.filters | 54 +++- doc/todo/VFALCO_TODO.txt | 5 + src/ripple_app/main/ripple_Application.cpp | 13 +- src/ripple_app/main/ripple_RippleMain.cpp | 6 +- src/ripple_app/rpc/RPCHandler.cpp | 10 +- src/ripple_basics/log/Log.cpp | 90 ++++++ src/ripple_basics/log/Log.h | 100 +++++++ .../ripple_LogFile.cpp => log/LogFile.cpp} | 0 .../ripple_LogFile.h => log/LogFile.h} | 4 +- src/ripple_basics/log/LogJournal.cpp | 24 ++ src/ripple_basics/log/LogJournal.h | 55 ++++ src/ripple_basics/log/LogPartition.cpp | 52 ++++ src/ripple_basics/log/LogPartition.h | 72 +++++ src/ripple_basics/log/LogSeverity.h | 21 ++ src/ripple_basics/log/LogSink.cpp | 176 +++++++++++ src/ripple_basics/log/LogSink.h | 81 +++++ .../LoggedTimings.h} | 4 +- src/ripple_basics/ripple_basics.cpp | 7 +- src/ripple_basics/ripple_basics.h | 10 +- src/ripple_basics/types/ripple_BasicTypes.h | 1 + src/ripple_basics/utility/ripple_Log.cpp | 282 ------------------ src/ripple_basics/utility/ripple_Log.h | 246 --------------- .../protocol/ripple_RippleAddress.cpp | 9 + .../protocol/ripple_RippleAddress.h | 5 + 25 files changed, 802 insertions(+), 577 deletions(-) create mode 100644 src/ripple_basics/log/Log.cpp create mode 100644 src/ripple_basics/log/Log.h rename src/ripple_basics/{utility/ripple_LogFile.cpp => log/LogFile.cpp} (100%) rename src/ripple_basics/{utility/ripple_LogFile.h => log/LogFile.h} (96%) create mode 100644 src/ripple_basics/log/LogJournal.cpp create mode 100644 src/ripple_basics/log/LogJournal.h create mode 100644 src/ripple_basics/log/LogPartition.cpp create mode 100644 src/ripple_basics/log/LogPartition.h create mode 100644 src/ripple_basics/log/LogSeverity.h create mode 100644 src/ripple_basics/log/LogSink.cpp create mode 100644 src/ripple_basics/log/LogSink.h rename src/ripple_basics/{utility/ripple_LoggedTimings.h => log/LoggedTimings.h} (96%) delete mode 100644 src/ripple_basics/utility/ripple_Log.cpp delete mode 100644 src/ripple_basics/utility/ripple_Log.h diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj index 95eb9aabdb..fc57846603 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj +++ b/Builds/VisualStudio2012/RippleD.vcxproj @@ -659,6 +659,36 @@ true true + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + true @@ -690,18 +720,6 @@ true true - - true - true - true - true - - - true - true - true - true - true true @@ -1497,6 +1515,13 @@ + + + + + + + @@ -1509,15 +1534,12 @@ - - - diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters index 8c41e44a0d..7c746036d9 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters @@ -172,6 +172,9 @@ {e614b68f-21cb-4866-82d1-1ea89ee11906} + + {824b1f04-7313-4abb-a3db-6241c7c8a356} + @@ -195,9 +198,6 @@ [1] Ripple\ripple_basics\utility - - [1] Ripple\ripple_basics\utility - [1] Ripple\ripple_basics\utility @@ -498,9 +498,6 @@ [1] Ripple\ripple_app - - [1] Ripple\ripple_basics\utility - [1] Ripple\ripple_data\protocol @@ -903,6 +900,21 @@ [1] Ripple\ripple_app\main + + [1] Ripple\ripple_basics\log + + + [1] Ripple\ripple_basics\log + + + [1] Ripple\ripple_basics\log + + + [1] Ripple\ripple_basics\log + + + [1] Ripple\ripple_basics\log + @@ -953,9 +965,6 @@ [1] Ripple\ripple_basics\utility - - [1] Ripple\ripple_basics\utility - [1] Ripple\ripple_basics\utility @@ -1280,9 +1289,6 @@ [0] Libraries\leveldb\port - - [1] Ripple\ripple_basics\utility - [1] Ripple\ripple_data\protocol @@ -1520,9 +1526,6 @@ [1] Ripple\ripple_app\main - - [1] Ripple\ripple_basics\utility - [1] Ripple\ripple_app\websocket @@ -1761,6 +1764,27 @@ [1] Ripple\ripple_app\main + + [1] Ripple\ripple_basics\log + + + [1] Ripple\ripple_basics\log + + + [1] Ripple\ripple_basics\log + + + [1] Ripple\ripple_basics\log + + + [1] Ripple\ripple_basics\log + + + [1] Ripple\ripple_basics\log + + + [1] Ripple\ripple_basics\log + diff --git a/doc/todo/VFALCO_TODO.txt b/doc/todo/VFALCO_TODO.txt index 5f8f70707a..32b3160b1d 100644 --- a/doc/todo/VFALCO_TODO.txt +++ b/doc/todo/VFALCO_TODO.txt @@ -3,6 +3,11 @@ RIPPLE TODO -------------------------------------------------------------------------------- Vinnie's List: Changes day to day, descending priority +- Fix and tidy up broken beast classes +- Parse Validator line using cribbed code +- Parse ContentBodyBuffer from HTTPResponse +- General cleanup of the repository and projcet files + - Look into using CMake - Validators should delay the application of newly downloaded lists from sources, to mitigate the effects of attacks. Unless there's no validators diff --git a/src/ripple_app/main/ripple_Application.cpp b/src/ripple_app/main/ripple_Application.cpp index 80a6e7f659..8a69f98b7d 100644 --- a/src/ripple_app/main/ripple_Application.cpp +++ b/src/ripple_app/main/ripple_Application.cpp @@ -11,6 +11,15 @@ class Application; SETUP_LOG (Application) +//------------------------------------------------------------------------------ +// +// Specializations for LogPartition names + +template <> char const* LogPartition::getPartitionName () { return "Validators"; } + +// +//------------------------------------------------------------------------------ + // VFALCO TODO Move the function definitions into the class declaration class ApplicationImp : public Application @@ -475,9 +484,9 @@ public: if (!getConfig ().DEBUG_LOGFILE.empty ()) { // Let debug messages go to the file but only WARNING or higher to regular output (unless verbose) - LogInstance::getInstance()->setLogFile (getConfig ().DEBUG_LOGFILE); + LogSink::get()->setLogFile (getConfig ().DEBUG_LOGFILE); - if (LogInstance::getInstance()->getMinSeverity () > lsDEBUG) + if (LogSink::get()->getMinSeverity () > lsDEBUG) LogPartition::setSeverity (lsDEBUG); } diff --git a/src/ripple_app/main/ripple_RippleMain.cpp b/src/ripple_app/main/ripple_RippleMain.cpp index 67fc5bc593..a9ec433a36 100644 --- a/src/ripple_app/main/ripple_RippleMain.cpp +++ b/src/ripple_app/main/ripple_RippleMain.cpp @@ -360,15 +360,15 @@ int RippleMain::run (int argc, char const* const* argv) if (vm.count ("quiet")) { - LogInstance::getInstance()->setMinSeverity (lsFATAL, true); + LogSink::get()->setMinSeverity (lsFATAL, true); } else if (vm.count ("verbose")) { - LogInstance::getInstance()->setMinSeverity (lsTRACE, true); + LogSink::get()->setMinSeverity (lsTRACE, true); } else { - LogInstance::getInstance()->setMinSeverity (lsINFO, true); + LogSink::get()->setMinSeverity (lsINFO, true); } // Run the unit tests if requested. diff --git a/src/ripple_app/rpc/RPCHandler.cpp b/src/ripple_app/rpc/RPCHandler.cpp index cd34247c78..e93ff2acc6 100644 --- a/src/ripple_app/rpc/RPCHandler.cpp +++ b/src/ripple_app/rpc/RPCHandler.cpp @@ -826,7 +826,7 @@ Json::Value RPCHandler::doProfile (Json::Value params, LoadType* loadType, Appli if (iArgs >= 8 && "false" != params[7u].asString()) bSubmit = true; - LogInstance::getInstance()->setMinSeverity(lsFATAL,true); + LogSink::get()->setMinSeverity(lsFATAL,true); boost::posix_time::ptime ptStart(boost::posix_time::microsec_clock::local_time()); @@ -2387,7 +2387,7 @@ Json::Value RPCHandler::doWalletAccounts (Json::Value params, LoadType* loadType Json::Value RPCHandler::doLogRotate (Json::Value, LoadType* loadType, Application::ScopedLockType& masterLockHolder) { - return LogInstance::getInstance()->rotateLog (); + return LogSink::get()->rotateLog (); } // { @@ -2592,7 +2592,7 @@ Json::Value RPCHandler::doLogLevel (Json::Value params, LoadType* loadType, Appl Json::Value ret (Json::objectValue); Json::Value lev (Json::objectValue); - lev["base"] = Log::severityToString (LogInstance::getInstance()->getMinSeverity ()); + lev["base"] = Log::severityToString (LogSink::get()->getMinSeverity ()); std::vector< std::pair > logTable = LogPartition::getSeverities (); typedef std::map::value_type stringPair; BOOST_FOREACH (const stringPair & it, logTable) @@ -2611,7 +2611,7 @@ Json::Value RPCHandler::doLogLevel (Json::Value params, LoadType* loadType, Appl if (!params.isMember ("partition")) { // set base log severity - LogInstance::getInstance()->setMinSeverity (sv, true); + LogSink::get()->setMinSeverity (sv, true); return Json::objectValue; } @@ -2622,7 +2622,7 @@ Json::Value RPCHandler::doLogLevel (Json::Value params, LoadType* loadType, Appl std::string partition (params["partition"].asString ()); if (boost::iequals (partition, "base")) - LogInstance::getInstance()->setMinSeverity (sv, false); + LogSink::get()->setMinSeverity (sv, false); else if (!LogPartition::setSeverity (partition, sv)) return rpcError (rpcINVALID_PARAMS); diff --git a/src/ripple_basics/log/Log.cpp b/src/ripple_basics/log/Log.cpp new file mode 100644 index 0000000000..e95ede65ed --- /dev/null +++ b/src/ripple_basics/log/Log.cpp @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +std::string Log::replaceFirstSecretWithAsterisks (std::string s) +{ + using namespace std; + + char const* secretToken = "\"secret\""; + + // Look for the first occurrence of "secret" in the string. + // + size_t startingPosition = s.find (secretToken); + + if (startingPosition != string::npos) + { + // Found it, advance past the token. + // + startingPosition += strlen (secretToken); + + // Replace the next 35 characters at most, without overwriting the end. + // + size_t endingPosition = std::min (startingPosition + 35, s.size () - 1); + + for (size_t i = startingPosition; i < endingPosition; ++i) + s [i] = '*'; + } + + return s; +} + +//------------------------------------------------------------------------------ + +Log::~Log () +{ + LogSink::get()->write (oss.str(), mSeverity, mPartitionName); +} + +std::string Log::severityToString (LogSeverity s) +{ + switch (s) + { + case lsTRACE: + return "Trace"; + + case lsDEBUG: + return "Debug"; + + case lsINFO: + return "Info"; + + case lsWARNING: + return "Warning"; + + case lsERROR: + return "Error"; + + case lsFATAL: + return "Fatal"; + + default: + assert (false); + return "Unknown"; + } +} + +LogSeverity Log::stringToSeverity (const std::string& s) +{ + if (boost::iequals (s, "trace")) + return lsTRACE; + + if (boost::iequals (s, "debug")) + return lsDEBUG; + + if (boost::iequals (s, "info") || boost::iequals (s, "information")) + return lsINFO; + + if (boost::iequals (s, "warn") || boost::iequals (s, "warning") || boost::iequals (s, "warnings")) + return lsWARNING; + + if (boost::iequals (s, "error") || boost::iequals (s, "errors")) + return lsERROR; + + if (boost::iequals (s, "fatal") || boost::iequals (s, "fatals")) + return lsFATAL; + + return lsINVALID; +} diff --git a/src/ripple_basics/log/Log.h b/src/ripple_basics/log/Log.h new file mode 100644 index 0000000000..c0e8b754cf --- /dev/null +++ b/src/ripple_basics/log/Log.h @@ -0,0 +1,100 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_LOG_H_INCLUDED +#define RIPPLE_BASICS_LOG_H_INCLUDED + +// A RAII helper for writing to the LogSink +// +class Log : public Uncopyable +{ +public: + explicit Log (LogSeverity s) : mSeverity (s) + { + } + + Log (LogSeverity s, LogPartition const& p) + : mSeverity (s) + , mPartitionName (p.getName ()) + { + } + + ~Log (); + + template + std::ostream& operator<< (const T& t) const + { + return oss << t; + } + + std::ostringstream& ref () const + { + return oss; + } + +public: + static std::string severityToString (LogSeverity); + + static LogSeverity stringToSeverity (std::string const&); + + /** Output stream for logging + + This is a convenient replacement for writing to `std::cerr`. + + Usage: + + @code + + Log::out () << "item1" << 2; + + @endcode + + It is not necessary to append a newline. + */ + class out + { + public: + out () + { + } + + ~out () + { + LogSink::get()->write (m_ss.str ()); + } + + template + out& operator<< (T t) + { + m_ss << t; + return *this; + } + + private: + std::stringstream m_ss; + }; + +private: + static std::string replaceFirstSecretWithAsterisks (std::string s); + + mutable std::ostringstream oss; + LogSeverity mSeverity; + std::string mPartitionName; +}; + +// Manually test for whether we should log +// +#define ShouldLog(s, k) (LogPartition::get ().doLog (s)) + +// Write to the log at the given severity level +// +#define WriteLog(s, k) if (!ShouldLog (s, k)) do {} while (0); else Log (s, LogPartition::get ()) + +// Write to the log conditionally +// +#define CondLog(c, s, k) if (!ShouldLog (s, k) || !(c)) do {} while(0); else Log(s, LogPartition::get ()) + +#endif diff --git a/src/ripple_basics/utility/ripple_LogFile.cpp b/src/ripple_basics/log/LogFile.cpp similarity index 100% rename from src/ripple_basics/utility/ripple_LogFile.cpp rename to src/ripple_basics/log/LogFile.cpp diff --git a/src/ripple_basics/utility/ripple_LogFile.h b/src/ripple_basics/log/LogFile.h similarity index 96% rename from src/ripple_basics/utility/ripple_LogFile.h rename to src/ripple_basics/log/LogFile.h index ca9bc34db1..e77b363835 100644 --- a/src/ripple_basics/utility/ripple_LogFile.h +++ b/src/ripple_basics/log/LogFile.h @@ -4,8 +4,8 @@ */ //============================================================================== -#ifndef RIPPLE_LOGFILE_H_INCLUDED -#define RIPPLE_LOGFILE_H_INCLUDED +#ifndef RIPPLE_BASICS_LOGFILE_H_INCLUDED +#define RIPPLE_BASICS_LOGFILE_H_INCLUDED /** Manages a system file containing logged output. diff --git a/src/ripple_basics/log/LogJournal.cpp b/src/ripple_basics/log/LogJournal.cpp new file mode 100644 index 0000000000..fba76bbb90 --- /dev/null +++ b/src/ripple_basics/log/LogJournal.cpp @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +LogSeverity LogJournal::convertSeverity (Journal::Severity severity) +{ + switch (severity) + { + case Journal::kTrace: return lsTRACE; + case Journal::kDebug: return lsDEBUG; + case Journal::kInfo: return lsINFO; + case Journal::kWarning: return lsWARNING; + case Journal::kError: return lsERROR; + + default: + bassertfalse; + case Journal::kFatal: + break; + } + + return lsFATAL; +} diff --git a/src/ripple_basics/log/LogJournal.h b/src/ripple_basics/log/LogJournal.h new file mode 100644 index 0000000000..f7f349364e --- /dev/null +++ b/src/ripple_basics/log/LogJournal.h @@ -0,0 +1,55 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_LOGJOURNAL_H_INCLUDED +#define RIPPLE_BASICS_LOGJOURNAL_H_INCLUDED + +/** Adapter that exports ripple::Log functionality as a Journal::Sink. */ +class LogJournal +{ +public: + /** Convert the Journal::Severity to a LogSeverity. */ + static LogSeverity convertSeverity (Journal::Severity severity); + + //-------------------------------------------------------------------------- + + /** A Journal::Sink that writes to the LogPartition with a given Key. */ + template + class PartitionSink : public Journal::Sink + { + public: + PartitionSink () + : m_partition (LogPartition::get ()) + { + } + + void write (Journal::Severity severity, std::string const& text) + { + // FIXME! + LogSink::get()->write (text, convertSeverity (severity), m_partition.getName()); + } + + bool active (Journal::Severity severity) + { + return m_partition.doLog (convertSeverity (severity)); + } + + private: + LogPartition const& m_partition; + }; + + //-------------------------------------------------------------------------- + + /** Returns a Journal outputting through the LogPartition for the Key. */ + template + static Journal get () + { + return Journal (SharedSingleton >::get ( + SingletonLifetime::neverDestroyed)); + } +}; + +#endif diff --git a/src/ripple_basics/log/LogPartition.cpp b/src/ripple_basics/log/LogPartition.cpp new file mode 100644 index 0000000000..7efd65e821 --- /dev/null +++ b/src/ripple_basics/log/LogPartition.cpp @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +LogPartition* LogPartition::headLog = NULL; + +LogPartition::LogPartition (char const* partitionName) + : mNextLog (headLog) + , mMinSeverity (lsWARNING) +{ + const char* ptr = strrchr (partitionName, '/'); + mName = (ptr == NULL) ? partitionName : (ptr + 1); + + size_t p = mName.find (".cpp"); + + if (p != std::string::npos) + mName.erase (mName.begin () + p, mName.end ()); + + headLog = this; +} + +std::vector< std::pair > LogPartition::getSeverities () +{ + std::vector< std::pair > sevs; + + for (LogPartition* l = headLog; l != NULL; l = l->mNextLog) + sevs.push_back (std::make_pair (l->mName, Log::severityToString (l->mMinSeverity))); + + return sevs; +} + +//------------------------------------------------------------------------------ + +bool LogPartition::setSeverity (const std::string& partition, LogSeverity severity) +{ + for (LogPartition* p = headLog; p != NULL; p = p->mNextLog) + if (boost::iequals (p->mName, partition)) + { + p->mMinSeverity = severity; + return true; + } + + return false; +} + +void LogPartition::setSeverity (LogSeverity severity) +{ + for (LogPartition* p = headLog; p != NULL; p = p->mNextLog) + p->mMinSeverity = severity; +} diff --git a/src/ripple_basics/log/LogPartition.h b/src/ripple_basics/log/LogPartition.h new file mode 100644 index 0000000000..3244c3fdc3 --- /dev/null +++ b/src/ripple_basics/log/LogPartition.h @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_LOGPARTITION_H_INCLUDED +#define RIPPLE_BASICS_LOGPARTITION_H_INCLUDED + +class LogPartition // : public List ::Node +{ +public: + LogPartition (const char* partitionName); + + /** Retrieve the LogPartition associated with an object. + + Each LogPartition is a singleton. + */ + template + static LogPartition const& get () + { + struct LogPartitionType : LogPartition + { + LogPartitionType () : LogPartition (getPartitionName ()) + { + } + }; + + return *SharedSingleton ::getInstance(); + } + + bool doLog (LogSeverity s) const + { + return s >= mMinSeverity; + } + + const std::string& getName () const + { + return mName; + } + + static bool setSeverity (const std::string& partition, LogSeverity severity); + static void setSeverity (LogSeverity severity); + static std::vector< std::pair > getSeverities (); + +private: + /** Retrieve the name for a log partition. + */ + template + static char const* getPartitionName (); + +private: + // VFALCO TODO Use an intrusive linked list + // + static LogPartition* headLog; + + LogPartition* mNextLog; + LogSeverity mMinSeverity; + std::string mName; +}; + +#define SETUP_LOG(Class) \ + template <> char const* LogPartition::getPartitionName () { return #Class; } \ + struct Class##Instantiator { Class##Instantiator () { LogPartition::get (); } }; \ + static Class##Instantiator Class##Instantiator_instance; + +#define SETUP_LOGN(Class,Name) \ + template <> char const* LogPartition::getPartitionName () { return Name; } \ + struct Class##Instantiator { Class##Instantiator () { LogPartition::get (); } }; \ + static Class##Instantiator Class##Instantiator_instance; + +#endif diff --git a/src/ripple_basics/log/LogSeverity.h b/src/ripple_basics/log/LogSeverity.h new file mode 100644 index 0000000000..cacd35365c --- /dev/null +++ b/src/ripple_basics/log/LogSeverity.h @@ -0,0 +1,21 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_LOGSEVERITY_H_INCLUDED +#define RIPPLE_BASICS_LOGSEVERITY_H_INCLUDED + +enum LogSeverity +{ + lsINVALID = -1, // used to indicate an invalid severity + lsTRACE = 0, // Very low-level progress information, details inside an operation + lsDEBUG = 1, // Function-level progress information, operations + lsINFO = 2, // Server-level progress information, major operations + lsWARNING = 3, // Conditions that warrant human attention, may indicate a problem + lsERROR = 4, // A condition that indicates a problem + lsFATAL = 5 // A severe condition that indicates a server problem +}; + +#endif diff --git a/src/ripple_basics/log/LogSink.cpp b/src/ripple_basics/log/LogSink.cpp new file mode 100644 index 0000000000..0c3e1ca43e --- /dev/null +++ b/src/ripple_basics/log/LogSink.cpp @@ -0,0 +1,176 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +LogSink::LogSink () + : m_mutex ("Log", __FILE__, __LINE__) + , m_minSeverity (lsINFO) +{ +} + +LogSink::~LogSink () +{ +} + +LogSeverity LogSink::getMinSeverity () +{ + ScopedLockType lock (m_mutex, __FILE__, __LINE__); + + return m_minSeverity; +} + +void LogSink::setMinSeverity (LogSeverity s, bool all) +{ + ScopedLockType lock (m_mutex, __FILE__, __LINE__); + + m_minSeverity = s; + + if (all) + LogPartition::setSeverity (s); +} + +void LogSink::setLogFile (boost::filesystem::path const& path) +{ + bool const wasOpened = m_logFile.open (path.c_str ()); + + if (! wasOpened) + { + Log (lsFATAL) << "Unable to open logfile " << path; + } +} + +std::string LogSink::rotateLog () +{ + ScopedLockType lock (m_mutex, __FILE__, __LINE__); + + bool const wasOpened = m_logFile.closeAndReopen (); + + if (wasOpened) + { + return "The log file was closed and reopened."; + } + else + { + return "The log file could not be closed and reopened."; + } +} + +void LogSink::write ( + std::string const& message, + LogSeverity severity, + std::string const& partitionName) +{ + std::string text; + text.reserve (message.size() + partitionName.size() + 100); + + text = boost::posix_time::to_simple_string ( + boost::posix_time::second_clock::universal_time ()); + + text += " "; + if (! partitionName.empty ()) + text += partitionName + ":"; + + switch (severity) + { + case lsTRACE: text += "TRC "; break; + case lsDEBUG: text += "DBG "; break; + case lsINFO: text += "NFO "; break; + case lsWARNING: text += "WRN "; break; + case lsERROR: text += "ERR "; break; + default: + bassertfalse; + case lsFATAL: text += "FTL "; + break; + } + + text += replaceFirstSecretWithAsterisks (message); + + if (text.size() > maximumMessageCharacters) + { + text.resize (maximumMessageCharacters - 3); + text += "..."; + } + + { + ScopedLockType lock (m_mutex, __FILE__, __LINE__); + + write (text, severity >= getMinSeverity(), lock); + } +} + +void LogSink::write (std::string const& text) +{ + ScopedLockType lock (m_mutex, __FILE__, __LINE__); + + write (text, true, lock); +} + +void LogSink::write (StringArray const& strings) +{ + ScopedLockType lock (m_mutex, __FILE__, __LINE__); + + for (int i = 0; i < strings.size (); ++i) + write (strings [i].toStdString (), true, lock); + +} + +void LogSink::write (std::string const& line, bool toStdErr, ScopedLockType&) +{ + // Does nothing if not open. + m_logFile.writeln (line); + + if (toStdErr) + { +#if BEAST_MSVC + if (beast_isRunningUnderDebugger ()) + { + // Send it to the attached debugger's Output window + // + Logger::outputDebugString (line); + } + else +#endif + { + std::cerr << line << std::endl; + } + } +} + +//------------------------------------------------------------------------------ + +std::string LogSink::replaceFirstSecretWithAsterisks (std::string s) +{ + using namespace std; + + char const* secretToken = "\"secret\""; + + // Look for the first occurrence of "secret" in the string. + // + size_t startingPosition = s.find (secretToken); + + if (startingPosition != string::npos) + { + // Found it, advance past the token. + // + startingPosition += strlen (secretToken); + + // Replace the next 35 characters at most, without overwriting the end. + // + size_t endingPosition = std::min (startingPosition + 35, s.size () - 1); + + for (size_t i = startingPosition; i < endingPosition; ++i) + s [i] = '*'; + } + + return s; +} + +//------------------------------------------------------------------------------ + +LogSink::Ptr LogSink::get () +{ + return SharedSingleton ::getInstance (); +} + diff --git a/src/ripple_basics/log/LogSink.h b/src/ripple_basics/log/LogSink.h new file mode 100644 index 0000000000..2f35e1ffbb --- /dev/null +++ b/src/ripple_basics/log/LogSink.h @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +#ifndef RIPPLE_BASICS_LOGSINK_H_INCLUDED +#define RIPPLE_BASICS_LOGSINK_H_INCLUDED + +/** An endpoint for all logging messages. */ +class LogSink +{ +public: + LogSink (); + ~LogSink (); + + /** Returns the minimum severity required for also writing to stderr. */ + LogSeverity getMinSeverity (); + + /** Sets the minimum severity required for also writing to stderr. */ + void setMinSeverity (LogSeverity, bool all); + + /** Sets the path to the log file. */ + void setLogFile (boost::filesystem::path const& pathToLogFile); + + /** Rotate the log file. + The log file is closed and reopened. This is for compatibility + with log management tools. + @return A human readable string describing the result of the operation. + */ + std::string rotateLog (); + + /** Write to log output. + + All logging eventually goes through this function. If a debugger + is attached, the string goes to the debugging console, else it goes + to the standard error output. If a log file is open, then the message + is additionally written to the open log file. + + The text should not contain a newline, it will be automatically + added as needed. + + @note This acquires a global mutex. + + @param text The text to write. + @param toStdErr `true` to also write to std::cerr + */ + /** @{ */ + void write (std::string const& message, + LogSeverity severity, std::string const& partitionName); + void write (std::string const& text); + void write (StringArray const& strings); + /** @} */ + + /** Hides secret keys from log output. */ + static std::string replaceFirstSecretWithAsterisks (std::string s); + + /** Returns a pointer to the singleton. */ + typedef SharedPtr > Ptr; + static Ptr get (); + +private: + typedef RippleRecursiveMutex LockType; + typedef LockType::ScopedLockType ScopedLockType; + + enum + { + /** Maximum line length for log messages. + If the message exceeds this length it will be truncated with elipses. + */ + maximumMessageCharacters = 12 * 1024 + }; + + void write (std::string const& line, bool toStdErr, ScopedLockType&); + + LockType m_mutex; + + LogFile m_logFile; + LogSeverity m_minSeverity; +}; +#endif diff --git a/src/ripple_basics/utility/ripple_LoggedTimings.h b/src/ripple_basics/log/LoggedTimings.h similarity index 96% rename from src/ripple_basics/utility/ripple_LoggedTimings.h rename to src/ripple_basics/log/LoggedTimings.h index ddc933f4bc..c2e17b055f 100644 --- a/src/ripple_basics/utility/ripple_LoggedTimings.h +++ b/src/ripple_basics/log/LoggedTimings.h @@ -4,8 +4,8 @@ */ //============================================================================== -#ifndef RIPPLE_LOGGEDTIMINGS_H_INCLUDED -#define RIPPLE_LOGGEDTIMINGS_H_INCLUDED +#ifndef RIPPLE_BASICS_LOGGEDTIMINGS_H_INCLUDED +#define RIPPLE_BASICS_LOGGEDTIMINGS_H_INCLUDED namespace detail { diff --git a/src/ripple_basics/ripple_basics.cpp b/src/ripple_basics/ripple_basics.cpp index 6de88267e2..86f38a93a3 100644 --- a/src/ripple_basics/ripple_basics.cpp +++ b/src/ripple_basics/ripple_basics.cpp @@ -79,8 +79,11 @@ namespace ripple #include "json/json_value.cpp" #include "json/json_writer.cpp" -#include "utility/ripple_Log.cpp" -#include "utility/ripple_LogFile.cpp" +#include "log/Log.cpp" +#include "log/LogFile.cpp" +#include "log/LogJournal.cpp" +#include "log/LogPartition.cpp" +#include "log/LogSink.cpp" #include "utility/ripple_ByteOrder.cpp" #include "utility/ripple_CountedObject.cpp" diff --git a/src/ripple_basics/ripple_basics.h b/src/ripple_basics/ripple_basics.h index ec70120b7a..71c132d655 100644 --- a/src/ripple_basics/ripple_basics.h +++ b/src/ripple_basics/ripple_basics.h @@ -94,8 +94,13 @@ using namespace beast; #include "types/ripple_BasicTypes.h" -#include "utility/ripple_LogFile.h" -#include "utility/ripple_Log.h" // Needed by others +# include "log/LogSeverity.h" +# include "log/LogFile.h" +# include "log/LogSink.h" +# include "log/LogPartition.h" +# include "log/Log.h" +#include "log/LogJournal.h" +#include "log/LoggedTimings.h" #include "utility/ripple_ByteOrder.h" #include "utility/ripple_CountedObject.h" @@ -107,7 +112,6 @@ using namespace beast; #include "utility/ripple_Sustain.h" #include "utility/ripple_ThreadName.h" #include "utility/ripple_Time.h" -#include "utility/ripple_LoggedTimings.h" #include "utility/ripple_UptimeTimer.h" #include "types/ripple_UInt256.h" diff --git a/src/ripple_basics/types/ripple_BasicTypes.h b/src/ripple_basics/types/ripple_BasicTypes.h index 2574c4e804..a845bc8c18 100644 --- a/src/ripple_basics/types/ripple_BasicTypes.h +++ b/src/ripple_basics/types/ripple_BasicTypes.h @@ -35,4 +35,5 @@ typedef UnsignedInteger <33> RipplePublicKey; /** A container holding the hash of a public key in binary format. */ typedef UnsignedInteger <20> RipplePublicKeyHash; + #endif diff --git a/src/ripple_basics/utility/ripple_Log.cpp b/src/ripple_basics/utility/ripple_Log.cpp deleted file mode 100644 index ab9a6053ca..0000000000 --- a/src/ripple_basics/utility/ripple_Log.cpp +++ /dev/null @@ -1,282 +0,0 @@ -//------------------------------------------------------------------------------ -/* - Copyright (c) 2011-2013, OpenCoin, Inc. -*/ -//============================================================================== - -LogPartition* LogPartition::headLog = NULL; - -LogPartition::LogPartition (char const* partitionName) - : mNextLog (headLog) - , mMinSeverity (lsWARNING) -{ - const char* ptr = strrchr (partitionName, '/'); - mName = (ptr == NULL) ? partitionName : (ptr + 1); - - size_t p = mName.find (".cpp"); - - if (p != std::string::npos) - mName.erase (mName.begin () + p, mName.end ()); - - headLog = this; -} - -std::vector< std::pair > LogPartition::getSeverities () -{ - std::vector< std::pair > sevs; - - for (LogPartition* l = headLog; l != NULL; l = l->mNextLog) - sevs.push_back (std::make_pair (l->mName, Log::severityToString (l->mMinSeverity))); - - return sevs; -} - -//------------------------------------------------------------------------------ - -std::string Log::replaceFirstSecretWithAsterisks (std::string s) -{ - using namespace std; - - char const* secretToken = "\"secret\""; - - // Look for the first occurrence of "secret" in the string. - // - size_t startingPosition = s.find (secretToken); - - if (startingPosition != string::npos) - { - // Found it, advance past the token. - // - startingPosition += strlen (secretToken); - - // Replace the next 35 characters at most, without overwriting the end. - // - size_t endingPosition = std::min (startingPosition + 35, s.size () - 1); - - for (size_t i = startingPosition; i < endingPosition; ++i) - s [i] = '*'; - } - - return s; -} - -//------------------------------------------------------------------------------ - -Log::~Log () -{ - std::string logMsg = boost::posix_time::to_simple_string (boost::posix_time::second_clock::universal_time ()); - - if (!mPartitionName.empty ()) - logMsg += " " + mPartitionName + ":"; - else - logMsg += " "; - - switch (mSeverity) - { - case lsTRACE: - logMsg += "TRC "; - break; - - case lsDEBUG: - logMsg += "DBG "; - break; - - case lsINFO: - logMsg += "NFO "; - break; - - case lsWARNING: - logMsg += "WRN "; - break; - - case lsERROR: - logMsg += "ERR "; - break; - - case lsFATAL: - logMsg += "FTL "; - break; - - case lsINVALID: - assert (false); - return; - } - - logMsg += replaceFirstSecretWithAsterisks (oss.str ()); - - if (logMsg.size () > maximumMessageCharacters) - { - logMsg.resize (maximumMessageCharacters); - logMsg += "..."; - } - - LogInstance::getInstance()->print (logMsg, mSeverity >= LogInstance::getInstance()->getMinSeverity ()); -} - -std::string Log::severityToString (LogSeverity s) -{ - switch (s) - { - case lsTRACE: - return "Trace"; - - case lsDEBUG: - return "Debug"; - - case lsINFO: - return "Info"; - - case lsWARNING: - return "Warning"; - - case lsERROR: - return "Error"; - - case lsFATAL: - return "Fatal"; - - default: - assert (false); - return "Unknown"; - } -} - -LogSeverity Log::stringToSeverity (const std::string& s) -{ - if (boost::iequals (s, "trace")) - return lsTRACE; - - if (boost::iequals (s, "debug")) - return lsDEBUG; - - if (boost::iequals (s, "info") || boost::iequals (s, "information")) - return lsINFO; - - if (boost::iequals (s, "warn") || boost::iequals (s, "warning") || boost::iequals (s, "warnings")) - return lsWARNING; - - if (boost::iequals (s, "error") || boost::iequals (s, "errors")) - return lsERROR; - - if (boost::iequals (s, "fatal") || boost::iequals (s, "fatals")) - return lsFATAL; - - return lsINVALID; -} - -bool LogPartition::setSeverity (const std::string& partition, LogSeverity severity) -{ - for (LogPartition* p = headLog; p != NULL; p = p->mNextLog) - if (boost::iequals (p->mName, partition)) - { - p->mMinSeverity = severity; - return true; - } - - return false; -} - -void LogPartition::setSeverity (LogSeverity severity) -{ - for (LogPartition* p = headLog; p != NULL; p = p->mNextLog) - p->mMinSeverity = severity; -} - -//------------------------------------------------------------------------------ - -LogInstance::LogInstance () - : m_mutex ("Log", __FILE__, __LINE__) - , m_minSeverity (lsINFO) -{ -} - -LogInstance::~LogInstance () -{ -} - -LogInstance* LogInstance::getInstance () -{ - return SharedSingleton ::getInstance (); -} - -LogSeverity LogInstance::getMinSeverity () -{ - ScopedLockType lock (m_mutex, __FILE__, __LINE__); - - return m_minSeverity; -} - -void LogInstance::setMinSeverity (LogSeverity s, bool all) -{ - ScopedLockType lock (m_mutex, __FILE__, __LINE__); - - m_minSeverity = s; - - if (all) - LogPartition::setSeverity (s); -} - -void LogInstance::setLogFile (boost::filesystem::path const& path) -{ - bool const wasOpened = m_logFile.open (path.c_str ()); - - if (! wasOpened) - { - Log (lsFATAL) << "Unable to open logfile " << path; - } -} - -std::string LogInstance::rotateLog () -{ - ScopedLockType lock (m_mutex, __FILE__, __LINE__); - - bool const wasOpened = m_logFile.closeAndReopen (); - - if (wasOpened) - { - return "The log file was closed and reopened."; - } - else - { - return "The log file could not be closed and reopened."; - } -} - -void LogInstance::print (std::string const& text, bool toStdErr) -{ - ScopedLockType lock (m_mutex, __FILE__, __LINE__); - - write (text, toStdErr); -} - -void LogInstance::print (StringArray const& strings, bool toStdErr) -{ - ScopedLockType lock (m_mutex, __FILE__, __LINE__); - - for (int i = 0; i < strings.size (); ++i) - write (strings [i].toStdString (), toStdErr); - -} - -void LogInstance::write (std::string const& line, bool toStdErr) -{ - // Does nothing if not open. - m_logFile.writeln (line); - - if (toStdErr) - { -#if 0 //BEAST_MSVC - if (beast_isRunningUnderDebugger ()) - { - // Send it to the attached debugger's Output window - // - Logger::outputDebugString (line); - } - else -#endif - { - std::cerr << line << std::endl; - } - } -} - diff --git a/src/ripple_basics/utility/ripple_Log.h b/src/ripple_basics/utility/ripple_Log.h deleted file mode 100644 index 7ee8eb37e4..0000000000 --- a/src/ripple_basics/utility/ripple_Log.h +++ /dev/null @@ -1,246 +0,0 @@ -//------------------------------------------------------------------------------ -/* - Copyright (c) 2011-2013, OpenCoin, Inc. -*/ -//============================================================================== - -#ifndef RIPPLE_LOG_H_INCLUDED -#define RIPPLE_LOG_H_INCLUDED - -enum LogSeverity -{ - lsINVALID = -1, // used to indicate an invalid severity - lsTRACE = 0, // Very low-level progress information, details inside an operation - lsDEBUG = 1, // Function-level progress information, operations - lsINFO = 2, // Server-level progress information, major operations - lsWARNING = 3, // Conditions that warrant human attention, may indicate a problem - lsERROR = 4, // A condition that indicates a problem - lsFATAL = 5 // A severe condition that indicates a server problem -}; - -//------------------------------------------------------------------------------ - -// VFALCO TODO make this a nested class in Log? -class LogPartition // : public List ::Node -{ -public: - LogPartition (const char* partitionName); - - /** Retrieve the LogPartition associated with an object. - - Each LogPartition is a singleton. - */ - template - static LogPartition const& get () - { - struct LogPartitionType : LogPartition - { - LogPartitionType () : LogPartition (getPartitionName ()) - { - } - }; - - return *SharedSingleton ::getInstance(); - } - - bool doLog (LogSeverity s) const - { - return s >= mMinSeverity; - } - - const std::string& getName () const - { - return mName; - } - - static bool setSeverity (const std::string& partition, LogSeverity severity); - static void setSeverity (LogSeverity severity); - static std::vector< std::pair > getSeverities (); - -private: - /** Retrieve the name for a log partition. - */ - template - static char const* getPartitionName (); - -private: - // VFALCO TODO Use an intrusive linked list - // - static LogPartition* headLog; - - LogPartition* mNextLog; - LogSeverity mMinSeverity; - std::string mName; -}; - -#define SETUP_LOG(Class) \ - template <> char const* LogPartition::getPartitionName () { return #Class; } \ - struct Class##Instantiator { Class##Instantiator () { LogPartition::get (); } }; \ - static Class##Instantiator Class##Instantiator_instance; - -#define SETUP_LOGN(Class,Name) \ - template <> char const* LogPartition::getPartitionName () { return Name; } \ - struct Class##Instantiator { Class##Instantiator () { LogPartition::get (); } }; \ - static Class##Instantiator Class##Instantiator_instance; - -//------------------------------------------------------------------------------ - -// A singleton which performs the actual logging. -// -class LogInstance -{ -public: - LogInstance (); - ~LogInstance (); - - static LogInstance* getInstance (); - - LogSeverity getMinSeverity (); - - void setMinSeverity (LogSeverity, bool all); - - void setLogFile (boost::filesystem::path const& pathToLogFile); - - /** Rotate the log file. - - The log file is closed and reopened. This is for compatibility - with log management tools. - - @return A human readable string describing the result of the operation. - */ - std::string rotateLog (); - - /** Write to log output. - - All logging eventually goes through this function. If a - debugger is attached, the string goes to the debugging console, - else it goes to the standard error output. If a log file is - open, then the message is additionally written to the open log - file. - - The text should not contain a newline, it will be automatically - added as needed. - - @note This acquires a global mutex. - - @param text The text to write. - @param toStdErr `true` to also write to std::cerr - */ - void print (std::string const& text, bool toStdErr = true); - - void print (StringArray const& strings, bool toStdErr = true); - -private: - void write (std::string const& line, bool toStdErr); - - typedef RippleRecursiveMutex LockType; - typedef LockType::ScopedLockType ScopedLockType; - LockType m_mutex; - - LogFile m_logFile; - LogSeverity m_minSeverity; -}; - -//------------------------------------------------------------------------------ - -// A RAII helper for writing to the LogInstance -// -class Log : public Uncopyable -{ -public: - explicit Log (LogSeverity s) : mSeverity (s) - { - } - - Log (LogSeverity s, LogPartition const& p) - : mSeverity (s) - , mPartitionName (p.getName ()) - { - } - - ~Log (); - - template - std::ostream& operator<< (const T& t) const - { - return oss << t; - } - - std::ostringstream& ref () const - { - return oss; - } - -public: - static std::string severityToString (LogSeverity); - - static LogSeverity stringToSeverity (std::string const&); - - /** Output stream for logging - - This is a convenient replacement for writing to `std::cerr`. - - Usage: - - @code - - Log::out () << "item1" << 2; - - @endcode - - It is not necessary to append a newline. - */ - class out - { - public: - out () - { - } - - ~out () - { - LogInstance::getInstance()->print (m_ss.str ()); - } - - template - out& operator<< (T t) - { - m_ss << t; - return *this; - } - - private: - std::stringstream m_ss; - }; - -private: - enum - { - /** Maximum line length for log messages. - - If the message exceeds this length it will be truncated - with elipses. - */ - maximumMessageCharacters = 12 * 1024 - }; - - static std::string replaceFirstSecretWithAsterisks (std::string s); - - mutable std::ostringstream oss; - LogSeverity mSeverity; - std::string mPartitionName; -}; - -// Manually test for whether we should log -// -#define ShouldLog(s, k) (LogPartition::get ().doLog (s)) - -// Write to the log at the given severity level -// -#define WriteLog(s, k) if (!ShouldLog (s, k)) do {} while (0); else Log (s, LogPartition::get ()) - -// Write to the log conditionally -// -#define CondLog(c, s, k) if (!ShouldLog (s, k) || !(c)) do {} while(0); else Log(s, LogPartition::get ()) - -#endif diff --git a/src/ripple_data/protocol/ripple_RippleAddress.cpp b/src/ripple_data/protocol/ripple_RippleAddress.cpp index 29249c2138..bb2f3e77c5 100644 --- a/src/ripple_data/protocol/ripple_RippleAddress.cpp +++ b/src/ripple_data/protocol/ripple_RippleAddress.cpp @@ -12,6 +12,15 @@ RippleAddress::RippleAddress () nVersion = VER_NONE; } +RipplePublicKey RippleAddress::toRipplePublicKey () const +{ + Blob const& b (getNodePublic ()); + + check_precondition (b.size () == RipplePublicKey::sizeInBytes); + + return RipplePublicKey (&b [0]); +} + void RippleAddress::clear () { nVersion = VER_NONE; diff --git a/src/ripple_data/protocol/ripple_RippleAddress.h b/src/ripple_data/protocol/ripple_RippleAddress.h index cb05b20d13..56a5cb43d1 100644 --- a/src/ripple_data/protocol/ripple_RippleAddress.h +++ b/src/ripple_data/protocol/ripple_RippleAddress.h @@ -31,6 +31,11 @@ private: public: RippleAddress (); + // Convert to a binary public key. If the underlying data + // is not appropriate, this will cause a fatal error. + // + RipplePublicKey toRipplePublicKey () const; + // For public and private key, checks if they are legal. bool isValid () const {