00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "rtabmap/utilite/ULogger.h"
00021 #include "rtabmap/utilite/UConversion.h"
00022 #include "rtabmap/utilite/UFile.h"
00023 #include "rtabmap/utilite/UStl.h"
00024 #include "rtabmap/utilite/UEventsManager.h"
00025 #include <fstream>
00026 #include <string>
00027 #include <string.h>
00028
00029 #ifndef _WIN32
00030 #include <sys/time.h>
00031 #endif
00032
00033 #ifdef _WIN32
00034 #include <Windows.h>
00035 #define COLOR_NORMAL FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
00036 #define COLOR_RED FOREGROUND_RED | FOREGROUND_INTENSITY
00037 #define COLOR_GREEN FOREGROUND_GREEN
00038 #define COLOR_YELLOW FOREGROUND_GREEN | FOREGROUND_RED
00039 #else
00040 #define COLOR_NORMAL "\033[0m"
00041 #define COLOR_RED "\033[31m"
00042 #define COLOR_GREEN "\033[32m"
00043 #define COLOR_YELLOW "\033[33m"
00044 #endif
00045
00046 bool ULogger::append_ = true;
00047 bool ULogger::printTime_ = true;
00048 bool ULogger::printLevel_ = true;
00049 bool ULogger::printEndline_ = true;
00050 bool ULogger::printColored_ = true;
00051 bool ULogger::printWhere_ = true;
00052 bool ULogger::printWhereFullPath_ = false;
00053 bool ULogger::printThreadID_ = false;
00054 bool ULogger::limitWhereLength_ = false;
00055 bool ULogger::buffered_ = false;
00056 ULogger::Level ULogger::level_ = kInfo;
00057 ULogger::Level ULogger::eventLevel_ = kFatal;
00058 const char * ULogger::levelName_[5] = {"DEBUG", " INFO", " WARN", "ERROR", "FATAL"};
00059 ULogger* ULogger::instance_ = 0;
00060 UDestroyer<ULogger> ULogger::destroyer_;
00061 ULogger::Type ULogger::type_ = ULogger::kTypeNoLog;
00062 UMutex ULogger::loggerMutex_;
00063 const std::string ULogger::kDefaultLogFileName = "./ULog.txt";
00064 std::string ULogger::logFileName_;
00065 std::string ULogger::bufferedMsgs_;
00066
00073 class UConsoleLogger : public ULogger
00074 {
00075 public :
00076 virtual ~UConsoleLogger() {this->_flush();}
00077
00078 protected:
00083 friend class ULogger;
00084
00085 UConsoleLogger() {}
00086
00087 private:
00088 virtual void _write(const char* msg, va_list arg)
00089 {
00090 vprintf(msg, arg);
00091 }
00092 virtual void _writeStr(const char* msg)
00093 {
00094 printf("%s", msg);
00095 }
00096 };
00097
00104 class UFileLogger : public ULogger
00105 {
00106 public:
00107 virtual ~UFileLogger()
00108 {
00109 this->_flush();
00110 if(fout_)
00111 {
00112 fclose(fout_);
00113 }
00114 }
00115
00116 protected:
00121 friend class ULogger;
00122
00130 UFileLogger(const std::string &fileName, bool append)
00131 {
00132 fileName_ = fileName;
00133
00134 if(!append) {
00135 std::ofstream fileToClear(fileName_.c_str(), std::ios::out);
00136 fileToClear.clear();
00137 fileToClear.close();
00138 }
00139
00140 #ifdef _MSC_VER
00141 fopen_s(&fout_, fileName_.c_str(), "a");
00142 #else
00143 fout_ = fopen(fileName_.c_str(), "a");
00144 #endif
00145
00146 if(!fout_) {
00147 printf("FileLogger : Cannot open file : %s\n", fileName_.c_str());
00148 return;
00149 }
00150 }
00151
00152 private:
00153 virtual void _write(const char* msg, va_list arg)
00154 {
00155 if(fout_)
00156 {
00157 vfprintf(fout_, msg, arg);
00158 }
00159 }
00160 virtual void _writeStr(const char* msg)
00161 {
00162 if(fout_)
00163 {
00164 fprintf(fout_, "%s", msg);
00165 }
00166 }
00167
00168 private:
00169 std::string fileName_;
00170 FILE* fout_;
00171 std::string bufferedMsgs_;
00172 };
00173
00174 void ULogger::setType(Type type, const std::string &fileName, bool append)
00175 {
00176 ULogger::flush();
00177 loggerMutex_.lock();
00178 {
00179
00180 if(!instance_)
00181 {
00182 type_ = type;
00183 logFileName_ = fileName;
00184 append_ = append;
00185 instance_ = createInstance();
00186 }
00187
00188 else if(type_ != type || (type_ == kTypeFile && logFileName_.compare(fileName)!=0))
00189 {
00190 destroyer_.setDoomed(0);
00191 delete instance_;
00192 instance_ = 0;
00193 type_ = type;
00194 logFileName_ = fileName;
00195 append_ = append;
00196 instance_ = createInstance();
00197 }
00198 }
00199 loggerMutex_.unlock();
00200 }
00201
00202 void ULogger::reset()
00203 {
00204 ULogger::setType(ULogger::kTypeNoLog);
00205 append_ = true;
00206 printTime_ = true;
00207 printLevel_ = true;
00208 printEndline_ = true;
00209 printColored_ = true;
00210 printWhere_ = true;
00211 printWhereFullPath_ = false;
00212 printThreadID_ = false;
00213 limitWhereLength_ = false;
00214 level_ = kInfo;
00215 logFileName_ = ULogger::kDefaultLogFileName;
00216 }
00217
00218 void ULogger::setBuffered(bool buffered)
00219 {
00220 if(!buffered)
00221 {
00222 ULogger::flush();
00223 }
00224 buffered_ = buffered;
00225 }
00226
00227
00228 void ULogger::flush()
00229 {
00230 loggerMutex_.lock();
00231 if(!instance_ || bufferedMsgs_.size()==0)
00232 {
00233 loggerMutex_.unlock();
00234 return;
00235 }
00236
00237 instance_->_flush();
00238 loggerMutex_.unlock();
00239 }
00240
00241 void ULogger::_flush()
00242 {
00243 ULogger::getInstance()->_writeStr(bufferedMsgs_.c_str());
00244 bufferedMsgs_.clear();
00245 }
00246
00247 void ULogger::write(const char* msg, ...)
00248 {
00249 loggerMutex_.lock();
00250 if(!instance_)
00251 {
00252 loggerMutex_.unlock();
00253 return;
00254 }
00255
00256 std::string endline = "";
00257 if(printEndline_) {
00258 endline = "\r\n";
00259 }
00260
00261 std::string time = "";
00262 if(printTime_)
00263 {
00264 getTime(time);
00265 time.append(" - ");
00266 }
00267
00268
00269 if(printTime_)
00270 {
00271 if(buffered_)
00272 {
00273 bufferedMsgs_.append(time.c_str());
00274 }
00275 else
00276 {
00277 ULogger::getInstance()->_writeStr(time.c_str());
00278 }
00279 }
00280
00281 va_list args;
00282 va_start(args, msg);
00283 if(buffered_)
00284 {
00285 bufferedMsgs_.append(uFormatv(msg, args));
00286 }
00287 else
00288 {
00289 ULogger::getInstance()->_write(msg, args);
00290 }
00291 va_end(args);
00292 if(printEndline_)
00293 {
00294 if(buffered_)
00295 {
00296 bufferedMsgs_.append(endline.c_str());
00297 }
00298 else
00299 {
00300 ULogger::getInstance()->_writeStr(endline.c_str());
00301 }
00302 }
00303 loggerMutex_.unlock();
00304
00305 }
00306
00307 void ULogger::write(ULogger::Level level,
00308 const char * file,
00309 int line,
00310 const char * function,
00311 const char* msg,
00312 ...)
00313 {
00314 loggerMutex_.lock();
00315 if(type_ == kTypeNoLog && level < kFatal && level < eventLevel_)
00316 {
00317 loggerMutex_.unlock();
00318 return;
00319 }
00320 if(strlen(msg) == 0 && !printWhere_ && level < kFatal)
00321 {
00322 loggerMutex_.unlock();
00323
00324 return;
00325 }
00326
00327 if(level >= level_ || level >= eventLevel_)
00328 {
00329 #ifdef _WIN32
00330 int color = 0;
00331 #else
00332 const char* color = NULL;
00333 #endif
00334 switch(level)
00335 {
00336 case kDebug:
00337 color = COLOR_GREEN;
00338 break;
00339 case kInfo:
00340 color = COLOR_NORMAL;
00341 break;
00342 case kWarning:
00343 color = COLOR_YELLOW;
00344 break;
00345 case kError:
00346 case kFatal:
00347 color = COLOR_RED;
00348 break;
00349 default:
00350 break;
00351 }
00352
00353 std::string endline = "";
00354 if(printEndline_) {
00355 endline = "\r\n";
00356 }
00357
00358 std::string time = "";
00359 if(printTime_ || level == kFatal)
00360 {
00361 time.append("(");
00362 getTime(time);
00363 time.append(") ");
00364 }
00365
00366 std::string levelStr = "";
00367 if(printLevel_ || level == kFatal)
00368 {
00369 const int bufSize = 30;
00370 char buf[bufSize] = {0};
00371
00372 #ifdef _MSC_VER
00373 sprintf_s(buf, bufSize, "[%s]", levelName_[level]);
00374 #else
00375 snprintf(buf, bufSize, "[%s]", levelName_[level]);
00376 #endif
00377 levelStr = buf;
00378 levelStr.append(" ");
00379 }
00380
00381 std::string pidStr;
00382 if(printThreadID_)
00383 {
00384 pidStr = uFormat("{%lu} ", UThread::currentThreadId());
00385 }
00386
00387 std::string whereStr = "";
00388 if(printWhere_ || level == kFatal)
00389 {
00390 whereStr.append("");
00391
00392 if(printWhereFullPath_)
00393 {
00394 whereStr.append(file);
00395 }
00396 else
00397 {
00398 std::string fileName = UFile::getName(file);
00399 if(limitWhereLength_ && fileName.size() > 8)
00400 {
00401 fileName.erase(8);
00402 fileName.append("~");
00403 }
00404 whereStr.append(fileName);
00405 }
00406
00407
00408 whereStr.append(":");
00409 std::string lineStr = uNumber2Str(line);
00410 whereStr.append(lineStr);
00411
00412
00413 whereStr.append("::");
00414 std::string funcStr = function;
00415 if(!printWhereFullPath_ && limitWhereLength_ && funcStr.size() > 8)
00416 {
00417 funcStr.erase(8);
00418 funcStr.append("~");
00419 }
00420 funcStr.append("()");
00421 whereStr.append(funcStr);
00422
00423 whereStr.append(" ");
00424 }
00425
00426 va_list args;
00427
00428 if(type_ != kTypeNoLog)
00429 {
00430 va_start(args, msg);
00431 #ifdef _WIN32
00432 HANDLE H = GetStdHandle(STD_OUTPUT_HANDLE);
00433 #endif
00434 if(type_ == ULogger::kTypeConsole && printColored_)
00435 {
00436 #ifdef _WIN32
00437 SetConsoleTextAttribute(H,color);
00438 #else
00439 if(buffered_)
00440 {
00441 bufferedMsgs_.append(color);
00442 }
00443 else
00444 {
00445 ULogger::getInstance()->_writeStr(color);
00446 }
00447 #endif
00448 }
00449
00450 if(buffered_)
00451 {
00452 bufferedMsgs_.append(levelStr.c_str());
00453 bufferedMsgs_.append(pidStr.c_str());
00454 bufferedMsgs_.append(time.c_str());
00455 bufferedMsgs_.append(whereStr.c_str());
00456 bufferedMsgs_.append(uFormatv(msg, args));
00457 }
00458 else
00459 {
00460 ULogger::getInstance()->_writeStr(levelStr.c_str());
00461 ULogger::getInstance()->_writeStr(pidStr.c_str());
00462 ULogger::getInstance()->_writeStr(time.c_str());
00463 ULogger::getInstance()->_writeStr(whereStr.c_str());
00464 ULogger::getInstance()->_write(msg, args);
00465 }
00466 if(type_ == ULogger::kTypeConsole && printColored_)
00467 {
00468 #ifdef _WIN32
00469 SetConsoleTextAttribute(H,COLOR_NORMAL);
00470 #else
00471 if(buffered_)
00472 {
00473 bufferedMsgs_.append(COLOR_NORMAL);
00474 }
00475 else
00476 {
00477 ULogger::getInstance()->_writeStr(COLOR_NORMAL);
00478 }
00479 #endif
00480 }
00481 if(buffered_)
00482 {
00483 bufferedMsgs_.append(endline.c_str());
00484 }
00485 else
00486 {
00487 ULogger::getInstance()->_writeStr(endline.c_str());
00488 }
00489 va_end (args);
00490 }
00491
00492 if(level >= eventLevel_)
00493 {
00494 std::string fullMsg = uFormat("%s%s%s%s", levelStr.c_str(), pidStr.c_str(), time.c_str(), whereStr.c_str());
00495 va_start(args, msg);
00496 fullMsg.append(uFormatv(msg, args));
00497 va_end(args);
00498 if(level >= kFatal)
00499 {
00500
00501
00502 UEventsManager::post(new ULogEvent(fullMsg, kFatal), false);
00503 }
00504 else
00505 {
00506 UEventsManager::post(new ULogEvent(fullMsg, level));
00507 }
00508 }
00509
00510 if(level >= kFatal)
00511 {
00512 std::string fullMsg = uFormat("%s%s%s%s", levelStr.c_str(), pidStr.c_str(), time.c_str(), whereStr.c_str());
00513 va_start(args, msg);
00514 fullMsg.append(uFormatv(msg, args));
00515 va_end(args);
00516
00517 if(instance_)
00518 {
00519 destroyer_.setDoomed(0);
00520 delete instance_;
00521 instance_ = 0;
00522 }
00523
00524
00525 loggerMutex_.unlock();
00526 throw UException(fullMsg);
00527
00528 }
00529 }
00530 loggerMutex_.unlock();
00531 }
00532
00533 int ULogger::getTime(std::string &timeStr)
00534 {
00535 struct tm timeinfo;
00536 const int bufSize = 30;
00537 char buf[bufSize] = {0};
00538
00539 #if _MSC_VER
00540 time_t rawtime;
00541 time(&rawtime);
00542 localtime_s (&timeinfo, &rawtime );
00543 int result = sprintf_s(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
00544 timeinfo.tm_year+1900,
00545 (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
00546 (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
00547 (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
00548 (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
00549 (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec);
00550 #elif WIN32
00551 time_t rawtime;
00552 time(&rawtime);
00553 timeinfo = *localtime (&rawtime);
00554 int result = snprintf(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
00555 timeinfo.tm_year+1900,
00556 (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
00557 (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
00558 (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
00559 (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
00560 (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec);
00561 #else
00562 struct timeval rawtime;
00563 gettimeofday(&rawtime, NULL);
00564 localtime_r (&rawtime.tv_sec, &timeinfo);
00565 int result = snprintf(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d.%s%d",
00566 timeinfo.tm_year+1900,
00567 (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
00568 (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
00569 (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
00570 (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
00571 (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec,
00572 (rawtime.tv_usec/1000) < 10 ? "00":(rawtime.tv_usec/1000) < 100?"0":"", int(rawtime.tv_usec/1000));
00573 #endif
00574 if(result)
00575 {
00576 timeStr.append(buf);
00577 }
00578 return result;
00579 }
00580
00581 ULogger* ULogger::getInstance()
00582 {
00583 if(!instance_)
00584 {
00585 instance_ = createInstance();
00586 }
00587 return instance_;
00588 }
00589
00590 ULogger* ULogger::createInstance()
00591 {
00592 ULogger* instance = 0;
00593 if(type_ == ULogger::kTypeConsole)
00594 {
00595 instance = new UConsoleLogger();
00596 }
00597 else if(type_ == ULogger::kTypeFile)
00598 {
00599 instance = new UFileLogger(logFileName_, append_);
00600 }
00601 destroyer_.setDoomed(instance);
00602 return instance;
00603 }
00604
00605 ULogger::~ULogger()
00606 {
00607 instance_ = 0;
00608
00609 }