00001 #ifndef Impala_Basis_Logger_h
00002 #define Impala_Basis_Logger_h
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "Basis/Timer.h"
00013
00014 #include <map>
00015 #include <iostream>
00016 #include <sstream>
00017 #include <fstream>
00018
00019
00020 namespace Impala
00021 {
00022
00023
00024 class LogListener
00025 {
00026 public:
00027 virtual void
00028 LogString(String, bool isPartial, int level) = 0;
00029
00030 virtual void
00031 EndLine(int level) = 0;
00032 };
00033
00034
00035 class LogType
00036 {
00037 public:
00038 LogType(int level, LogListener *target)
00039 {
00040 mLevel = level;
00041 mLogger = target;
00042 }
00043
00044 LogType&
00045 operator<<(String log)
00046 {
00047 mLogger->LogString(log, true, mLevel);
00048 return *this;
00049 }
00050
00051 template <class T>
00052 LogType&
00053 operator<<(T log)
00054 {
00055 std::ostringstream s;
00056 s << log;
00057 mLogger->LogString(s.str(), true, mLevel);
00058 return *this;
00059 }
00060
00061 LogType&
00062 operator<<( std::ostream& (*f)(std::ostream&) )
00063 {
00064 mLogger->EndLine(mLevel);
00065 return *this;
00066 }
00067
00068 private:
00069 int mLevel;
00070 LogListener *mLogger;
00071 };
00072
00073
00074 class Logger : public LogListener
00075 {
00076 public:
00077
00078 static void
00079 Configure(int logLevel, String logFile, bool debug)
00080 {
00081 GetInstance().Init(logLevel, logFile, debug);
00082 }
00083
00084 static LogType
00085 Debug(int level=Logger::LOG_DEBUG)
00086 {
00087 return Log(level);
00088 }
00089
00090 static LogType
00091 Log(int level=Logger::LOG_INFO)
00092 {
00093 return LogType(level, &Logger::GetInstance());
00094 }
00095
00096 static LogType
00097 User()
00098 {
00099 return Log(Logger::LOG_USER);
00100 }
00101
00102 static LogType
00103 System()
00104 {
00105 return Log(Logger::LOG_SYSTEM);
00106 }
00107
00108 static LogType
00109 Error()
00110 {
00111 return Log(Logger::LOG_ERROR);
00112 }
00113
00114 static LogType
00115 Warning()
00116 {
00117 return Log(Logger::LOG_WARNING);
00118 }
00119
00120 static LogType
00121 Information()
00122 {
00123 return Log(Logger::LOG_INFO);
00124 }
00125
00126 virtual
00127 ~Logger()
00128 {
00129 LogString("Logger destructed.");
00130 if (mLogToFile)
00131 mLog->close();
00132 mErrorLog->close();
00133 }
00134
00135 static const int LOG_DEBUG = 1;
00136 static const int LOG_INFO = 2;
00137 static const int LOG_WARNING = 3;
00138 static const int LOG_ERROR = 4;
00139 static const int LOG_ACTION = 5;
00140 static const int LOG_SYSTEM = 6;
00141 static const int LOG_USER = 7;
00142
00143 static void
00144 StartAction(String actionName, int level=LOG_USER)
00145 {
00146 Logger *al = &GetInstance();
00147 al->mActionTimes[actionName] = al->mTimer->SplitTime();
00148 al->mActionLevels[actionName] = level;
00149 std::ostringstream s;
00150 s << "ACTION START: " << actionName;
00151 al->LogString(s.str(), false, level);
00152 }
00153
00154 static double
00155 EndAction(String actionName)
00156 {
00157 Logger *al = &GetInstance();
00158 if (al->mActionTimes.find(actionName) == al->mActionTimes.end())
00159 {
00160 Warning() << "EndAction called but no action started: "
00161 << actionName << std::endl;
00162 return 0.0;
00163 }
00164
00165 double delta = al->mTimer->SplitTime() - al->mActionTimes[actionName];
00166 std::ostringstream s;
00167 s << "ACTION STOP: " << actionName << ", " << delta << " seconds";
00168 al->LogString(s.str(), false, al->mActionLevels[actionName]);
00169 return delta;
00170 }
00171
00172 static void
00173 OpenPartLog()
00174 {
00175 Logger *al = &GetInstance();
00176 al->DoOpenPartLog();
00177 }
00178
00179 static void
00180 ClosePartLog(String filename)
00181 {
00182 Logger *al = &GetInstance();
00183 al->DoClosePartLog(filename);
00184 }
00185
00186
00187 protected:
00188
00189 virtual void
00190 LogString(String log, bool isPartial=false, int level=LOG_DEBUG)
00191 {
00192 if (level < mShowLevel)
00193 return;
00194
00195 if (!mLineStarted)
00196 {
00197 std::cout << mTimer->SplitTimeStr() << " " << GetHeader(level)
00198 << ": ";
00199 if (mLogToFile)
00200 *mLog << mTimer->SplitTime() << " " << GetHeader(level) << ": ";
00201 if (mPLog != 0)
00202 *mPLog << mTimer->SplitTime() << " " << GetHeader(level) << ": ";
00203 if (level == LOG_ERROR)
00204 *mErrorLog << mTimer->SplitTime() << " " << GetHeader(level)
00205 << ": ";
00206 }
00207
00208 std::cout << log;
00209
00210 if (mLogToFile)
00211 *mLog << log;
00212 if (mPLog != 0)
00213 *mPLog << log;
00214 if (level == LOG_ERROR)
00215 *mErrorLog << log;
00216
00217 mLineStarted = true;
00218 if (!isPartial)
00219 EndLine(level);
00220 }
00221
00222 void
00223 EndLine(int level)
00224 {
00225 if (mLineStarted)
00226 {
00227 std::cout << std::endl;
00228 if (mLogToFile)
00229 *mLog << std::endl;
00230 if (mPLog != 0)
00231 *mPLog << std::endl;
00232 if (level == LOG_ERROR)
00233 *mErrorLog << std::endl;
00234
00235 mLineStarted = false;
00236 }
00237 }
00238
00239 String
00240 GetHeader(int level)
00241 {
00242 switch (level)
00243 {
00244 case LOG_DEBUG: return "DEBUG ";
00245 case LOG_INFO: return "INFO ";
00246 case LOG_WARNING:return "WARNING ";
00247 case LOG_ERROR: return "ERROR ";
00248 case LOG_ACTION: return "ACTION ";
00249 case LOG_SYSTEM: return "SYSTEM ";
00250 case LOG_USER: return "USER ";
00251 }
00252 return "?? ";
00253 }
00254
00255 void
00256 DoOpenPartLog()
00257 {
00258 if (mPLog != 0)
00259 {
00260 LogString("DoOpenPartLog: closing last part log.");
00261 delete mPLog;
00262 }
00263 mPLog = new std::ostringstream();
00264 LogString("Partial log started.");
00265 }
00266
00267 void
00268 DoClosePartLog(String filename)
00269 {
00270 std::ostringstream s;
00271 s << "Writing partial log to file " << filename;
00272 LogString(s.str());
00273 std::fstream f(filename.c_str(), std::ios::out);
00274 f << mPLog->str();
00275 f << std::endl;
00276 f.close();
00277 delete mPLog;
00278 mPLog = 0;
00279 }
00280
00281 public:
00282
00283 Logger&
00284 operator<<(String log)
00285 {
00286 LogString(log, true, LOG_DEBUG);
00287 return *this;
00288 }
00289
00290 Logger&
00291 operator<<( std::ostream& (*f)(std::ostream&) )
00292 {
00293 EndLine(mShowLevel);
00294 return *this;
00295 }
00296
00297
00298 private:
00299
00300 static Logger&
00301 GetInstance()
00302 {
00303 static Logger theLogger;
00304 return theLogger;
00305 }
00306
00307 Logger()
00308 {
00309 }
00310
00311 void
00312 Init(int logLevel, String logFile, bool debug)
00313 {
00314 mLineStarted = false;
00315 mTimer = new Timer(1);
00316
00317 mShowLevel = logLevel;
00318 mLogFile = logFile;
00319 mLogToFile = !mLogFile.empty();
00320 if (debug)
00321 mShowLevel = LOG_DEBUG;
00322
00323 std::ostringstream s;
00324 s << "Logger started @ level " << mShowLevel;
00325
00326 if (mLogToFile)
00327 {
00328 mLog = new std::fstream(mLogFile.c_str(),
00329 std::ios::out | std::ios::app);
00330 }
00331 else
00332 {
00333 mLog = 0;
00334 }
00335 mPLog = 0;
00336 mErrorLog = new std::fstream("errors.log", std::ios::out | std::ios::app);
00337 LogString(s.str());
00338 }
00339
00340 std::map<String, double> mActionTimes;
00341 std::map<String, int> mActionLevels;
00342 String mLogFile;
00343 bool mLogToFile;
00344 bool mLineStarted;
00345 int mShowLevel;
00346 Timer *mTimer;
00347 std::fstream *mLog;
00348 std::ostringstream *mPLog;
00349 std::fstream *mErrorLog;
00350
00351 };
00352
00353 }
00354
00355 #endif