//------------------------------------------------------------------------------ /* 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 () { static LogPartition logPartition (getPartitionName ()); return logPartition; } 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; //------------------------------------------------------------------------------ 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; } static std::string severityToString (LogSeverity); static LogSeverity stringToSeverity (std::string const&); static LogSeverity getMinSeverity (); static void setMinSeverity (LogSeverity, bool all); static 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. */ static std::string rotateLog (); public: /** 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 */ static void print (std::string const& text, bool toStdErr = true); /** 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 () { Log::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); // Singleton variables // static LogFile s_logFile; static boost::recursive_mutex s_lock; static LogSeverity sMinSeverity; 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 // vim:ts=4