00001 #pragma ident "$Id: logstream.hpp 2293 2010-02-12 18:14:16Z btolman $"
00002
00008 #ifndef LOGSTREAMINCLUDE
00009 #define LOGSTREAMINCLUDE
00010
00011 #include <sstream>
00012 #include <string>
00013 #include <iostream>
00014
00018 enum LogLevel {ERROR, WARNING, INFO, VERBOSE, DEBUG,
00019 DEBUG1, DEBUG2, DEBUG3, DEBUG4, DEBUG5, DEBUG6, DEBUG7 };
00021 #ifndef FILELOG_MAX_LEVEL
00022 #define FILELOG_MAX_LEVEL DEBUG7
00023 #endif
00024
00027 template <class T> class Log
00028 {
00029 public:
00030 Log() {};
00031 virtual ~Log();
00033 std::ostringstream& Put(LogLevel level = INFO);
00034
00036 static bool& ReportTimeTags();
00038 static bool& ReportLevels();
00040 static LogLevel& ReportingLevel();
00042 static std::string ToString(LogLevel level);
00044 static LogLevel FromString(const std::string& level);
00045
00046 protected:
00048 std::ostringstream os;
00049
00050 #ifdef WIN32 // see kludge note below
00051 static LogLevel reportingLevel;
00052 static bool dumpTimeTags;
00053 static bool dumpLevels;
00054 #endif
00055
00056 private:
00057 Log(const Log&);
00058 Log& operator=(const Log&);
00059 std::string NowTime(void);
00060 };
00061
00062 template <class T> std::ostringstream& Log<T>::Put(LogLevel level)
00063 {
00064 if(Log<T>::ReportTimeTags()) os << NowTime() << " ";
00065 if(Log<T>::ReportLevels()) {
00066 os << ToString(level) << ": ";
00067
00068 if(level > DEBUG) os << std::string(2*(level-DEBUG),' ');
00069 }
00070 return os;
00071 }
00072
00073 template <class T> Log<T>::~Log()
00074 {
00075 os << std::endl;
00076 T::Output(os.str());
00077 }
00078
00079 template <class T> bool& Log<T>::ReportLevels()
00080 {
00081 #ifndef WIN32 // see kludge note below
00082 static bool dumpLevels = false;
00083 #endif
00084 return dumpLevels;
00085 }
00086
00087 template <class T> bool& Log<T>::ReportTimeTags()
00088 {
00089 #ifndef WIN32 // see kludge note below
00090 static bool dumpTimeTags = false;
00091 #endif
00092 return dumpTimeTags;
00093 }
00094
00095 template <class T> LogLevel& Log<T>::ReportingLevel()
00096 {
00097 #ifndef WIN32 // see kludge note below
00098 static LogLevel reportingLevel = INFO;
00099 #endif
00100 return reportingLevel;
00101 }
00102
00103 template <class T> std::string Log<T>::ToString(LogLevel level)
00104 {
00105
00106 static const char* const buffer[] = {"ERROR", "WARNING", "INFO", "VERBOSE",
00107 "DEBUG","DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4", "DEBUG5", "DEBUG6", "DEBUG7" };
00108 return buffer[level];
00109 }
00110
00111 template <class T> LogLevel Log<T>::FromString(const std::string& level)
00112 {
00113
00114 if(level == "DEBUG7") return DEBUG7;
00115 if(level == "DEBUG6") return DEBUG6;
00116 if(level == "DEBUG5") return DEBUG5;
00117 if(level == "DEBUG4") return DEBUG4;
00118 if(level == "DEBUG3") return DEBUG3;
00119 if(level == "DEBUG2") return DEBUG2;
00120 if(level == "DEBUG1") return DEBUG1;
00121 if(level == "DEBUG") return DEBUG;
00122 if(level == "VERBOSE") return VERBOSE;
00123 if(level == "INFO") return INFO;
00124 if(level == "WARNING") return WARNING;
00125 if(level == "ERROR") return ERROR;
00126 Log<T>().Put(WARNING)
00127 << "Unknown logging level '" << level << "'. Using INFO level instead.";
00128 return INFO;
00129 }
00130
00131
00132
00133 #ifdef WIN32
00134 #include <sys/timeb.h>
00135 template <class T> inline std::string Log<T>::NowTime()
00136 {
00137 _timeb t;
00138 _ftime(&t);
00139 long sec=t.time;
00140 double dt=double(sec)+t.millitm/1000.;
00141 sec -= long(dt/86400)*86400;
00142 dt = double(sec)+t.millitm/1000.;
00143 char result[100] = {0};
00144 int h=int(dt/3600.);
00145 dt -= h*3600.;
00146 int m=int(dt/60.);
00147 dt -= m*60.;
00148 int s=int(dt);
00149 dt -= s;
00150 std::sprintf(result,"%02d:%02d:%02d.%03d",h,m,s,int(dt*1000.));
00151 return result;
00152 }
00153
00154 #else // not WIN32
00155
00156 #include <sys/time.h>
00157 template <class T> inline std::string Log<T>::NowTime()
00158 {
00159 char buffer[11];
00160 time_t t;
00161 time(&t);
00162 tm r = {0};
00163 strftime(buffer, sizeof(buffer), "%X", localtime_r(&t, &r));
00164 struct timeval tv;
00165 gettimeofday(&tv, 0);
00166 char result[100] = {0};
00167 std::sprintf(result, "%s.%03ld", buffer, (long)tv.tv_usec / 1000);
00168 return result;
00169 }
00170
00171 #endif //WIN32
00172
00173
00174
00235 class ConfigureLOGstream
00236 {
00237 public:
00243 static std::ostream*& Stream();
00244
00246 static void Output(const std::string& msg);
00247 };
00248
00249 inline std::ostream*& ConfigureLOGstream::Stream()
00250 {
00251 static std::ostream *pStream = &(std::cout);
00252 return pStream;
00253 }
00254
00255 inline void ConfigureLOGstream::Output(const std::string& msg)
00256 {
00257 std::ostream *pStream = Stream();
00258 if(!pStream) return;
00259 *pStream << msg << std::flush;
00260 }
00261
00262
00263
00265 class ConfigureLOG : public Log<ConfigureLOGstream> {
00266 public:
00267 static std::ostream*& Stream()
00268 { return ConfigureLOGstream::Stream(); }
00269 static LogLevel Level(const std::string& str)
00270 { return FromString(str); }
00271 };
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286 #ifdef WIN32
00287
00288
00289 template<> LogLevel Log<ConfigureLOGstream>::reportingLevel = INFO;
00290 template<> bool Log<ConfigureLOGstream>::dumpTimeTags = false;
00291 template<> bool Log<ConfigureLOGstream>::dumpLevels = false;
00292
00293 #endif
00294
00296 #define LOG(level) \
00297 if(level > FILELOG_MAX_LEVEL) ;\
00298 else if(level > ConfigureLOG::ReportingLevel() || !ConfigureLOGstream::Stream()) ;\
00299 else ConfigureLOG().Put(level)
00300
00301
00302 #define pLOGstrm ConfigureLOGstream::Stream()
00303 #define LOGstrm *(ConfigureLOGstream::Stream())
00304 #define LOGlevel ConfigureLOG::ReportingLevel()
00305
00306
00307
00311
00312
00313
00314 #endif //LOGSTREAMINCLUDE --- end of the include file. Test code follows in comments.
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446