00001 //---------------------------------------------------------------------------- 00002 /** @file Logger.hpp 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #ifndef HEXLOGGER_HPP 00007 #define HEXLOGGER_HPP 00008 00009 #include <fstream> 00010 #include <iostream> 00011 #include <sstream> 00012 #include <vector> 00013 #include <map> 00014 #include <pthread.h> 00015 #include "Benzene.hpp" 00016 00017 _BEGIN_BENZENE_NAMESPACE_ 00018 00019 //---------------------------------------------------------------------------- 00020 00021 /** Levels for messages to a Logger object. */ 00022 enum LogLevel 00023 { 00024 /** All messages with levels higher than OFF are ignored. */ 00025 LOG_LEVEL_OFF = 65536, 00026 00027 /** Message level indicating a serious failure. 00028 In general a severe message should describe events of considerable 00029 importance which will prevent normal program execution. 00030 */ 00031 LOG_LEVEL_SEVERE = 1000, 00032 00033 /** Message level indicating a potential problem. 00034 Should be used to describe events of interest to users and 00035 developers. 00036 */ 00037 LOG_LEVEL_WARNING = 900, 00038 00039 /** Message level for informational messages. 00040 Messages of this level or higher are typically output on the 00041 console. 00042 */ 00043 LOG_LEVEL_INFO = 800, 00044 00045 /** Message level for configuration purposes. 00046 Should be used to provide a variety of static configuration 00047 information to assist in debugging. 00048 */ 00049 LOG_LEVEL_CONFIG = 700, 00050 00051 /** Message level providing tracing information. */ 00052 LOG_LEVEL_FINE = 500, 00053 00054 /** Message level providing more tracing information. */ 00055 LOG_LEVEL_FINER = 300, 00056 00057 /** Special level indicating that all messages should be 00058 logged. */ 00059 LOG_LEVEL_ALL = 0 00060 }; 00061 00062 /** Utilities on LogLevel. */ 00063 namespace LogLevelUtil 00064 { 00065 /** Returns true if the given level is valid. */ 00066 bool IsValidLevel(LogLevel level); 00067 00068 /** Returns a string representation of the level. */ 00069 std::string toString(LogLevel level); 00070 00071 /** Converts a string to a LogLevel. */ 00072 LogLevel fromString(std::string); 00073 } 00074 00075 //---------------------------------------------------------------------------- 00076 00077 /** Logger supporting message levels and multiple output streams 00078 received from multiple threads. 00079 00080 A Logger can have several streams. Each stream is assigned a level. 00081 When the Logger receives a message at level L, all streams with level 00082 at least L will be sent a copy of the message. 00083 00084 Logger handles messages coming from multiple threads internally. A 00085 LogLevel for each thread is maintained, and separate buffers are 00086 used for messages being formed simulataneously in different 00087 threads. Blocking is used to grant a thread exclusive access to 00088 the streams when printing; this potentially could cause slowdown 00089 if several threads are dumping lots of text simultaneously. 00090 */ 00091 class Logger 00092 { 00093 public: 00094 00095 /** Creates a logger object. By default, log outputs to std::cerr 00096 at LOG_LEVEL_INFO. */ 00097 Logger(); 00098 00099 /** Destructor. */ 00100 ~Logger(); 00101 00102 /** Returns the global Logger object. */ 00103 static Logger& Global(); 00104 00105 /** Adds a handler to this logger at the given level. */ 00106 void AddStream(std::ostream& stream, LogLevel level); 00107 00108 /** Removes all output streams. */ 00109 void ClearStreams(); 00110 00111 /** Sets the level of all messages this logger receives from now 00112 on. */ 00113 void SetLevel(LogLevel level); 00114 00115 /** Flushes the log. */ 00116 void Flush(); 00117 00118 /** Pipes text into the log. If text ends in a '\n', log is 00119 flushed. */ 00120 template<typename TYPE> 00121 Logger& operator<<(const TYPE& type); 00122 00123 private: 00124 00125 /** Maximum number of threads handled at once. */ 00126 static const int MAX_THREADS = 16; 00127 00128 /** Buffer for a thread of execution. */ 00129 struct ThreadBuffer 00130 { 00131 std::ostringstream buffer; 00132 pthread_t id; 00133 }; 00134 00135 /** Returns the buffer for the current thread. */ 00136 ThreadBuffer& GetThreadBuffer(); 00137 00138 /** Returns the current loglevel for the thread. */ 00139 LogLevel GetThreadLevel(); 00140 00141 /** Streams for this log. */ 00142 std::vector<std::ostream*> m_streams; 00143 00144 /** Level for each stream. */ 00145 std::vector<LogLevel> m_levels; 00146 00147 /** Threads must grab this mutex before modifying m_thread_buffer 00148 or printing output. */ 00149 pthread_mutex_t m_buffer_mutex; 00150 00151 /** Buffers for up to MAX_THREADS active threads. */ 00152 ThreadBuffer m_thread_buffer[MAX_THREADS]; 00153 00154 /** Threads must grab this mutex before modifying 00155 m_thread_level. */ 00156 pthread_mutex_t m_map_mutex; 00157 00158 /** Current log level for each thread. */ 00159 std::map<pthread_t, LogLevel> m_thread_level; 00160 }; 00161 00162 template<typename TYPE> 00163 Logger& Logger::operator<<(const TYPE& type) 00164 { 00165 ThreadBuffer& tb = GetThreadBuffer(); 00166 tb.buffer << type; 00167 std::string str(tb.buffer.str()); 00168 if (!str.empty() && str[str.size() - 1] == '\n') 00169 Flush(); 00170 return *this; 00171 } 00172 00173 //---------------------------------------------------------------------------- 00174 00175 /** Sets global logger to LOG_LEVEL_FINE. */ 00176 inline Logger& LogFine() 00177 { 00178 Logger::Global().SetLevel(LOG_LEVEL_FINE); 00179 return Logger::Global(); 00180 } 00181 00182 /** Similar to LogFine() */ 00183 inline Logger& LogConfig() 00184 { 00185 Logger::Global().SetLevel(LOG_LEVEL_CONFIG); 00186 return Logger::Global(); 00187 } 00188 00189 /** Similar to LogFine() */ 00190 inline Logger& LogInfo() 00191 { 00192 Logger::Global().SetLevel(LOG_LEVEL_INFO); 00193 return Logger::Global(); 00194 } 00195 00196 /** Similar to LogFine() */ 00197 inline Logger& LogWarning() 00198 { 00199 Logger::Global().SetLevel(LOG_LEVEL_WARNING); 00200 return Logger::Global(); 00201 } 00202 00203 /** Similar to LogFine() */ 00204 inline Logger& LogSevere() 00205 { 00206 Logger::Global().SetLevel(LOG_LEVEL_SEVERE); 00207 return Logger::Global(); 00208 } 00209 00210 //---------------------------------------------------------------------------- 00211 00212 _END_BENZENE_NAMESPACE_ 00213 00214 #endif // LOGGER_HPP