00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #ifndef __LOG2_H_INCLUDED
00038 #define __LOG2_H_INCLUDED
00039
00040 #include <map>
00041 #include <vector>
00042
00043 #include "Log.h"
00044
00045 #define STRINGIFY(x) #x
00046 #define TOSTRING(x) STRINGIFY(x)
00047 #define AT __FILE__ ":" TOSTRING(__LINE__)
00048
00049 #define LOG2(obj, str, level) do {if ((level) >= (obj).getLevel()) { CCriticalSection logsection((obj).getStream()); (obj)(level) << str;}} while (0)
00050
00051 #ifdef DEBUG
00052 #define logCrawl(obj, str) LOG2(obj, str, llCrawl)
00053 #else
00054 #define logCrawl(obj, str) do {} while (0)
00055 #endif
00056
00057 #define logDebug(obj, str) LOG2(obj, str, llDebug)
00058 #define logInfo(obj, str) LOG2(obj, str, llInfo)
00059 #define logNotice(obj, str) LOG2(obj, str, llNotice)
00060 #define logWarning(obj, str) LOG2(obj, str, llWarning)
00061 #define logError(obj, str) LOG2(obj, str, llError)
00062 #define logCritical(obj, str) LOG2(obj, str, llCritical)
00063 #define logClean(obj, str) LOG2(obj, str, llClean)
00064
00065 #define logCrawlLn(obj, str) logCrawl(obj, str << std::endl)
00066 #define logDebugLn(obj, str) logDebug(obj, str << std::endl)
00067 #define logInfoLn(obj, str) logInfo(obj, str << std::endl)
00068 #define logNoticeLn(obj, str) logNotice(obj, str << std::endl)
00069 #define logWarningLn(obj, str) logWarning(obj, str << std::endl)
00070 #define logErrorLn(obj, str) logError(obj, str << std::endl)
00071 #define logCriticalLn(obj, str) logCritical(obj, str << std::endl)
00072 #define logCleanLn(obj, str) logClean(obj, str << std::endl)
00073
00074 #define mLogCrawl(str) logCrawl(mLog, str)
00075 #define mLogDebug(str) logDebug(mLog, str)
00076 #define mLogInfo(str) logInfo(mLog, str)
00077 #define mLogNotice(str) logNotice(mLog, str)
00078 #define mLogWarning(str) logWarning(mLog, str)
00079 #define mLogError(str) logError(mLog, str)
00080 #define mLogCritical(str) logCritical(mLog, str)
00081 #define mLogClean(str) logClean(mLog, str)
00082
00083 #define mLogCrawlLn(str) logCrawlLn(mLog, str)
00084 #define mLogDebugLn(str) logDebugLn(mLog, str)
00085 #define mLogInfoLn(str) logInfoLn(mLog, str)
00086 #define mLogNoticeLn(str) logNoticeLn(mLog, str)
00087 #define mLogWarningLn(str) logWarningLn(mLog, str)
00088 #define mLogErrorLn(str) logErrorLn(mLog, str)
00089 #define mLogCriticalLn(str) logCriticalLn(mLog, str)
00090 #define mLogCleanLn(str) logCleanLn(mLog, str)
00091 #define mLogAssert(B) logAssertLnInternal(mLog, "Assertion failed at " AT ": " #B, llError, B)
00092
00093
00094 #define LOG2HDRDELIMLEFT "["
00095 #define LOG2HDRDELIMRIGHT "] "
00096 #define LOG2OPENFILESSOFTLIMIT 100 // This is a soft limit. You can open more files, but this may lead to memory (re)allocation (unwanted in real-time apps).
00097
00098
00099 class CLog2;
00100
00101 class CLog2Factory
00102 {
00103 friend class CLog2;
00104 protected:
00105 ELogLevel mLevel;
00106 bool mTimeStamping;
00107 std::map<const std::string, CLogStream*> mLogs;
00108 std::vector<FILE*> mOpenFiles;
00109
00115 void equalizeHeaderTexts()
00116 {
00117 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
00118
00119 pthread_mutex_lock(&mutex);
00120
00121
00122 unsigned int maxWidth=0;
00123 for (std::map<const std::string, CLogStream*>::iterator it = mLogs.begin();
00124 it != mLogs.end(); ++it)
00125 {
00126 if (it->second->headerText().length() > maxWidth)
00127 maxWidth = it->second->headerText().length();
00128 }
00129
00130
00131 for (std::map<const std::string, CLogStream*>::iterator it = mLogs.begin();
00132 it != mLogs.end(); ++it)
00133 {
00134
00135 if (!it->second->headerText().empty())
00136 {
00137 it->second->headerText().resize(maxWidth, ' ');
00138
00139 std::string delimitStr(LOG2HDRDELIMRIGHT);
00140 std::string::size_type delimitLoc = it->second->headerText().rfind(delimitStr);
00141
00142 if (delimitLoc != std::string::npos)
00143 it->second->headerText().erase(delimitLoc, delimitStr.length()).append(delimitStr);
00144 }
00145 }
00146
00147 pthread_mutex_unlock(&mutex);
00148 }
00149
00150
00151
00152
00153 void reportOpenFile(FILE* file, CLogStream& wrnReportLog)
00154 {
00155 if (file != NULL)
00156 {
00157 mOpenFiles.push_back(file);
00158 if (mOpenFiles.size() >= LOG2OPENFILESSOFTLIMIT)
00159 wrnReportLog << "[WARNING] Open file limit of log factory exceeded: memory allocation may occur. Try and increase LOG2OPENFILESSOFTLIMIT." << std::endl;
00160 }
00161 }
00162 void closeOpenFiles()
00163 {
00164 while (!mOpenFiles.empty())
00165 {
00166 fclose(mOpenFiles.back());
00167 mOpenFiles.pop_back();
00168 }
00169 }
00170
00171 public:
00172 CLog2Factory() : mLevel(llInfo), mTimeStamping(false)
00173 {
00174 mOpenFiles.reserve(LOG2OPENFILESSOFTLIMIT);
00175 }
00176 virtual ~CLog2Factory()
00177 {
00178
00179 closeOpenFiles();
00180
00181 for (std::map<const std::string, CLogStream*>::iterator it = mLogs.begin();
00182 it != mLogs.end(); ++it)
00183 delete it->second;
00184 }
00185
00186
00187 virtual void setLevel(ELogLevel level)
00188 {
00189 mLevel = level;
00190
00191 for (std::map<const std::string, CLogStream*>::iterator it = mLogs.begin();
00192 it != mLogs.end(); ++it)
00193 it->second->setLevel(mLevel);
00194 }
00195 virtual CLogStream &getLog(const std::string &name) = 0;
00196
00197 virtual void enableConsoleOutput(bool bEnabled)
00198 {
00199 for (std::map<const std::string, CLogStream*>::iterator it = mLogs.begin();
00200 it != mLogs.end(); ++it)
00201 it->second->enableConsoleOutput(bEnabled);
00202 }
00203 virtual void enableFileOutput(bool bEnabled, const std::string& filename="")
00204 {
00205 for (std::map<const std::string, CLogStream*>::iterator it = mLogs.begin();
00206 it != mLogs.end(); ++it)
00207 reportOpenFile(it->second->enableFileOutput(bEnabled, filename), *(it->second));
00208 }
00209 virtual void enableTimeStamping(bool bEnabled)
00210 {
00211 mTimeStamping = bEnabled;
00212
00213 for (std::map<const std::string, CLogStream*>::iterator it = mLogs.begin();
00214 it != mLogs.end(); ++it)
00215 it->second->enableTimeStamping(bEnabled);
00216 }
00217 virtual void flushFileOutput()
00218 {
00219 for (std::map<const std::string, CLogStream*>::iterator it = mLogs.begin();
00220 it != mLogs.end(); ++it)
00221 it->second->flushFileOutput();
00222 }
00223 virtual void redirectConsoleOutput(FILE* file)
00224 {
00225 for (std::map<const std::string, CLogStream*>::iterator it = mLogs.begin();
00226 it != mLogs.end(); ++it)
00227 it->second->redirectConsoleOutput(file);
00228 }
00229 virtual ELogLevel getLevelFromString(const std::string &level)
00230 {
00231 if (!level.compare(0, 3, "cra")) return llCrawl;
00232 if (!level.compare(0, 1, "d")) return llDebug;
00233 if (!level.compare(0, 1, "i")) return llInfo;
00234 if (!level.compare(0, 1, "n")) return llNotice;
00235 if (!level.compare(0, 1, "w")) return llWarning;
00236 if (!level.compare(0, 1, "e")) return llError;
00237 if (!level.compare(0, 3, "cri")) return llCritical;
00238 return llInfo;
00239 }
00240 };
00241
00242
00243
00244 CLog2Factory& gLogFactory();
00245
00246 class CLog2
00247 {
00248 private:
00249 CLogStream &mStream;
00250 std::string mName;
00251
00252 public:
00253 CLog2(const std::string &name) :
00254 mStream(gLogFactory().getLog(name)),
00255 mName(name)
00256 { }
00257 CLog2& operator=(const CLog2 &obj) { return *this; }
00258
00259 CLogStream &operator()(ELogLevel level)
00260 {
00261 switch (level)
00262 {
00263 case llCrawl:
00264 mStream.setMessageColor(FOREGROUND_GREEN);
00265 mStream.setSystemHeader("CRL: ");
00266 break;
00267 case llDebug:
00268 mStream.setMessageColor(FOREGROUND_GREEN);
00269 mStream.setSystemHeader("DBG: ");
00270 break;
00271 case llInfo:
00272 mStream.setMessageColor(FOREGROUND_GRAY);
00273 mStream.setSystemHeader("INF: ");
00274 break;
00275 case llNotice:
00276 mStream.setMessageColor(FOREGROUND_BLUE);
00277 mStream.setSystemHeader("NTC: ");
00278 break;
00279 case llWarning:
00280 mStream.setMessageColor(FOREGROUND_BROWN);
00281 mStream.setSystemHeader("WRN: ");
00282 break;
00283 case llError:
00284 mStream.setMessageColor(FOREGROUND_RED);
00285 mStream.setSystemHeader("ERR: ");
00286 break;
00287 case llCritical:
00288 mStream.setMessageColor(FOREGROUND_MAGENTA);
00289 mStream.setSystemHeader("CRT: ");
00290 break;
00291 case llClean:
00292
00293 mStream.setSystemHeader("");
00294 break;
00295 }
00296
00297 return mStream;
00298 }
00299
00300 const std::string& name() { return mName; }
00301
00302 inline ELogLevel getLevel() const { return mStream.getLevel(); }
00303 void setLevel(ELogLevel level) { mStream.setLevel(level); }
00304 void enableTimeStamping(bool bEnabled) { mStream.enableTimeStamping(bEnabled); }
00305 void setHeaderText(const std::string &text) { CCriticalSection setheader(mStream); mStream.setHeaderText(text); }
00306 void setHeaderColor(int color) { mStream.setHeaderColor(color); }
00307 void enableConsoleOutput(bool bEnabled) { mStream.enableConsoleOutput(bEnabled); }
00308 void enableFileOutput(bool bEnabled, const std::string& filename="") { gLogFactory().reportOpenFile(mStream.enableFileOutput(bEnabled, filename), (*this)(llWarning)); }
00309 void flushFileOutput() { mStream.flushFileOutput(); }
00310 CLogStream &getStream() { return mStream; }
00311 };
00312
00313 inline bool logAssertLnInternal(CLog2& log, const char *msg, ELogLevel level, bool condition)
00314 {
00315 if (!condition)
00316 LOG2(log, msg << std::endl, level);
00317 return condition;
00318 }
00319
00320 #endif