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 std::set<unsigned long> ULogger::threadIdFilter_;
00067 std::map<std::string, unsigned long> ULogger::registeredThreads_;
00068
00075 class UConsoleLogger : public ULogger
00076 {
00077 public :
00078 virtual ~UConsoleLogger() {this->_flush();}
00079
00080 protected:
00085 friend class ULogger;
00086
00087 UConsoleLogger() {}
00088
00089 private:
00090 virtual void _write(const char* msg, va_list arg)
00091 {
00092 vprintf(msg, arg);
00093 }
00094 virtual void _writeStr(const char* msg)
00095 {
00096 printf("%s", msg);
00097 }
00098 };
00099
00106 class UFileLogger : public ULogger
00107 {
00108 public:
00109 virtual ~UFileLogger()
00110 {
00111 this->_flush();
00112 if(fout_)
00113 {
00114 fclose(fout_);
00115 }
00116 }
00117
00118 protected:
00123 friend class ULogger;
00124
00132 UFileLogger(const std::string &fileName, bool append)
00133 {
00134 fileName_ = fileName;
00135
00136 if(!append) {
00137 std::ofstream fileToClear(fileName_.c_str(), std::ios::out);
00138 fileToClear.clear();
00139 fileToClear.close();
00140 }
00141
00142 #ifdef _MSC_VER
00143 fopen_s(&fout_, fileName_.c_str(), "a");
00144 #else
00145 fout_ = fopen(fileName_.c_str(), "a");
00146 #endif
00147
00148 if(!fout_) {
00149 printf("FileLogger : Cannot open file : %s\n", fileName_.c_str());
00150 return;
00151 }
00152 }
00153
00154 private:
00155 virtual void _write(const char* msg, va_list arg)
00156 {
00157 if(fout_)
00158 {
00159 vfprintf(fout_, msg, arg);
00160 }
00161 }
00162 virtual void _writeStr(const char* msg)
00163 {
00164 if(fout_)
00165 {
00166 fprintf(fout_, "%s", msg);
00167 }
00168 }
00169
00170 private:
00171 std::string fileName_;
00172 FILE* fout_;
00173 std::string bufferedMsgs_;
00174 };
00175
00176 void ULogger::setType(Type type, const std::string &fileName, bool append)
00177 {
00178 ULogger::flush();
00179 loggerMutex_.lock();
00180 {
00181
00182 if(!instance_)
00183 {
00184 type_ = type;
00185 logFileName_ = fileName;
00186 append_ = append;
00187 instance_ = createInstance();
00188 }
00189
00190 else if(type_ != type || (type_ == kTypeFile && logFileName_.compare(fileName)!=0))
00191 {
00192 destroyer_.setDoomed(0);
00193 delete instance_;
00194 instance_ = 0;
00195 type_ = type;
00196 logFileName_ = fileName;
00197 append_ = append;
00198 instance_ = createInstance();
00199 }
00200 }
00201 loggerMutex_.unlock();
00202 }
00203
00204 void ULogger::setTreadIdFilter(const std::vector<std::string> & ids)
00205 {
00206 loggerMutex_.lock();
00207 threadIdFilter_.clear();
00208 for(unsigned int i=0;i<ids.size();++i)
00209 {
00210 if(registeredThreads_.find(ids[i]) != registeredThreads_.end())
00211 {
00212 threadIdFilter_.insert(registeredThreads_.at(ids[i]));
00213 }
00214 }
00215 loggerMutex_.unlock();
00216 }
00217
00218 void ULogger::registerCurrentThread(const std::string & name)
00219 {
00220 loggerMutex_.lock();
00221 UASSERT(!name.empty());
00222 uInsert(registeredThreads_, std::make_pair(name, UThread::currentThreadId()));
00223 loggerMutex_.unlock();
00224 }
00225
00226 void ULogger::unregisterCurrentThread()
00227 {
00228 loggerMutex_.lock();
00229
00230 unsigned long id = UThread::currentThreadId();
00231 for(std::map<std::string, unsigned long>::iterator iter=registeredThreads_.begin(); iter!=registeredThreads_.end();)
00232 {
00233 if(iter->second == id)
00234 {
00235 registeredThreads_.erase(iter++);
00236 threadIdFilter_.erase(id);
00237 }
00238 else
00239 {
00240 ++iter;
00241 }
00242 }
00243
00244 loggerMutex_.unlock();
00245 }
00246
00247 std::map<std::string, unsigned long> ULogger::getRegisteredThreads()
00248 {
00249 loggerMutex_.lock();
00250 std::map<std::string, unsigned long> out = registeredThreads_;
00251 loggerMutex_.unlock();
00252 return out;
00253 }
00254
00255 void ULogger::reset()
00256 {
00257 ULogger::setType(ULogger::kTypeNoLog);
00258 append_ = true;
00259 printTime_ = true;
00260 printLevel_ = true;
00261 printEndline_ = true;
00262 printColored_ = true;
00263 printWhere_ = true;
00264 printWhereFullPath_ = false;
00265 printThreadID_ = false;
00266 limitWhereLength_ = false;
00267 level_ = kInfo;
00268 logFileName_ = ULogger::kDefaultLogFileName;
00269 }
00270
00271 void ULogger::setBuffered(bool buffered)
00272 {
00273 if(!buffered)
00274 {
00275 ULogger::flush();
00276 }
00277 buffered_ = buffered;
00278 }
00279
00280
00281 void ULogger::flush()
00282 {
00283 loggerMutex_.lock();
00284 if(!instance_ || bufferedMsgs_.size()==0)
00285 {
00286 loggerMutex_.unlock();
00287 return;
00288 }
00289
00290 instance_->_flush();
00291 loggerMutex_.unlock();
00292 }
00293
00294 void ULogger::_flush()
00295 {
00296 ULogger::getInstance()->_writeStr(bufferedMsgs_.c_str());
00297 bufferedMsgs_.clear();
00298 }
00299
00300 void ULogger::write(const char* msg, ...)
00301 {
00302 loggerMutex_.lock();
00303 if(!instance_)
00304 {
00305 loggerMutex_.unlock();
00306 return;
00307 }
00308
00309 std::string endline = "";
00310 if(printEndline_) {
00311 endline = "\r\n";
00312 }
00313
00314 std::string time = "";
00315 if(printTime_)
00316 {
00317 getTime(time);
00318 time.append(" - ");
00319 }
00320
00321
00322 if(printTime_)
00323 {
00324 if(buffered_)
00325 {
00326 bufferedMsgs_.append(time.c_str());
00327 }
00328 else
00329 {
00330 ULogger::getInstance()->_writeStr(time.c_str());
00331 }
00332 }
00333
00334 va_list args;
00335 va_start(args, msg);
00336 if(buffered_)
00337 {
00338 bufferedMsgs_.append(uFormatv(msg, args));
00339 }
00340 else
00341 {
00342 ULogger::getInstance()->_write(msg, args);
00343 }
00344 va_end(args);
00345 if(printEndline_)
00346 {
00347 if(buffered_)
00348 {
00349 bufferedMsgs_.append(endline.c_str());
00350 }
00351 else
00352 {
00353 ULogger::getInstance()->_writeStr(endline.c_str());
00354 }
00355 }
00356 loggerMutex_.unlock();
00357
00358 }
00359
00360 void ULogger::write(ULogger::Level level,
00361 const char * file,
00362 int line,
00363 const char * function,
00364 const char* msg,
00365 ...)
00366 {
00367 loggerMutex_.lock();
00368 if(type_ == kTypeNoLog && level < kFatal && level < eventLevel_)
00369 {
00370 loggerMutex_.unlock();
00371 return;
00372 }
00373 if(strlen(msg) == 0 && !printWhere_ && level < kFatal)
00374 {
00375 loggerMutex_.unlock();
00376
00377 return;
00378 }
00379 if(level < kFatal &&
00380 threadIdFilter_.size() &&
00381 threadIdFilter_.find(UThread::currentThreadId()) == threadIdFilter_.end())
00382 {
00383 loggerMutex_.unlock();
00384 return;
00385 }
00386
00387 if(level >= level_ || level >= eventLevel_)
00388 {
00389 #ifdef _WIN32
00390 int color = 0;
00391 #else
00392 const char* color = NULL;
00393 #endif
00394 switch(level)
00395 {
00396 case kDebug:
00397 color = COLOR_GREEN;
00398 break;
00399 case kInfo:
00400 color = COLOR_NORMAL;
00401 break;
00402 case kWarning:
00403 color = COLOR_YELLOW;
00404 break;
00405 case kError:
00406 case kFatal:
00407 color = COLOR_RED;
00408 break;
00409 default:
00410 break;
00411 }
00412
00413 std::string endline = "";
00414 if(printEndline_) {
00415 endline = "\r\n";
00416 }
00417
00418 std::string time = "";
00419 if(printTime_ || level == kFatal)
00420 {
00421 time.append("(");
00422 getTime(time);
00423 time.append(") ");
00424 }
00425
00426 std::string levelStr = "";
00427 if(printLevel_ || level == kFatal)
00428 {
00429 const int bufSize = 30;
00430 char buf[bufSize] = {0};
00431
00432 #ifdef _MSC_VER
00433 sprintf_s(buf, bufSize, "[%s]", levelName_[level]);
00434 #else
00435 snprintf(buf, bufSize, "[%s]", levelName_[level]);
00436 #endif
00437 levelStr = buf;
00438 levelStr.append(" ");
00439 }
00440
00441 std::string pidStr;
00442 if(printThreadID_)
00443 {
00444 pidStr = uFormat("{%lu} ", UThread::currentThreadId());
00445 }
00446
00447 std::string whereStr = "";
00448 if(printWhere_ || level == kFatal)
00449 {
00450 whereStr.append("");
00451
00452 if(printWhereFullPath_)
00453 {
00454 whereStr.append(file);
00455 }
00456 else
00457 {
00458 std::string fileName = UFile::getName(file);
00459 if(limitWhereLength_ && fileName.size() > 8)
00460 {
00461 fileName.erase(8);
00462 fileName.append("~");
00463 }
00464 whereStr.append(fileName);
00465 }
00466
00467
00468 whereStr.append(":");
00469 std::string lineStr = uNumber2Str(line);
00470 whereStr.append(lineStr);
00471
00472
00473 whereStr.append("::");
00474 std::string funcStr = function;
00475 if(!printWhereFullPath_ && limitWhereLength_ && funcStr.size() > 8)
00476 {
00477 funcStr.erase(8);
00478 funcStr.append("~");
00479 }
00480 funcStr.append("()");
00481 whereStr.append(funcStr);
00482
00483 whereStr.append(" ");
00484 }
00485
00486 va_list args;
00487
00488 if(type_ != kTypeNoLog)
00489 {
00490 va_start(args, msg);
00491 #ifdef _WIN32
00492 HANDLE H = GetStdHandle(STD_OUTPUT_HANDLE);
00493 #endif
00494 if(type_ == ULogger::kTypeConsole && printColored_)
00495 {
00496 #ifdef _WIN32
00497 SetConsoleTextAttribute(H,color);
00498 #else
00499 if(buffered_)
00500 {
00501 bufferedMsgs_.append(color);
00502 }
00503 else
00504 {
00505 ULogger::getInstance()->_writeStr(color);
00506 }
00507 #endif
00508 }
00509
00510 if(buffered_)
00511 {
00512 bufferedMsgs_.append(levelStr.c_str());
00513 bufferedMsgs_.append(pidStr.c_str());
00514 bufferedMsgs_.append(time.c_str());
00515 bufferedMsgs_.append(whereStr.c_str());
00516 bufferedMsgs_.append(uFormatv(msg, args));
00517 }
00518 else
00519 {
00520 ULogger::getInstance()->_writeStr(levelStr.c_str());
00521 ULogger::getInstance()->_writeStr(pidStr.c_str());
00522 ULogger::getInstance()->_writeStr(time.c_str());
00523 ULogger::getInstance()->_writeStr(whereStr.c_str());
00524 ULogger::getInstance()->_write(msg, args);
00525 }
00526 if(type_ == ULogger::kTypeConsole && printColored_)
00527 {
00528 #ifdef _WIN32
00529 SetConsoleTextAttribute(H,COLOR_NORMAL);
00530 #else
00531 if(buffered_)
00532 {
00533 bufferedMsgs_.append(COLOR_NORMAL);
00534 }
00535 else
00536 {
00537 ULogger::getInstance()->_writeStr(COLOR_NORMAL);
00538 }
00539 #endif
00540 }
00541 if(buffered_)
00542 {
00543 bufferedMsgs_.append(endline.c_str());
00544 }
00545 else
00546 {
00547 ULogger::getInstance()->_writeStr(endline.c_str());
00548 }
00549 va_end (args);
00550 }
00551
00552 if(level >= eventLevel_)
00553 {
00554 std::string fullMsg = uFormat("%s%s%s%s", levelStr.c_str(), pidStr.c_str(), time.c_str(), whereStr.c_str());
00555 va_start(args, msg);
00556 fullMsg.append(uFormatv(msg, args));
00557 va_end(args);
00558 if(level >= kFatal)
00559 {
00560
00561
00562 UEventsManager::post(new ULogEvent(fullMsg, kFatal), false);
00563 }
00564 else
00565 {
00566 UEventsManager::post(new ULogEvent(fullMsg, level));
00567 }
00568 }
00569
00570 if(level >= kFatal)
00571 {
00572 std::string fullMsg = uFormat("%s%s%s%s", levelStr.c_str(), pidStr.c_str(), time.c_str(), whereStr.c_str());
00573 va_start(args, msg);
00574 fullMsg.append(uFormatv(msg, args));
00575 va_end(args);
00576
00577 if(instance_)
00578 {
00579 destroyer_.setDoomed(0);
00580 delete instance_;
00581 instance_ = 0;
00582 }
00583
00584
00585 loggerMutex_.unlock();
00586 throw UException(fullMsg);
00587
00588 }
00589 }
00590 loggerMutex_.unlock();
00591 }
00592
00593 int ULogger::getTime(std::string &timeStr)
00594 {
00595 struct tm timeinfo;
00596 const int bufSize = 30;
00597 char buf[bufSize] = {0};
00598
00599 #if _MSC_VER
00600 time_t rawtime;
00601 time(&rawtime);
00602 localtime_s (&timeinfo, &rawtime );
00603 int result = sprintf_s(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
00604 timeinfo.tm_year+1900,
00605 (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
00606 (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
00607 (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
00608 (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
00609 (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec);
00610 #elif WIN32
00611 time_t rawtime;
00612 time(&rawtime);
00613 timeinfo = *localtime (&rawtime);
00614 int result = snprintf(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
00615 timeinfo.tm_year+1900,
00616 (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
00617 (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
00618 (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
00619 (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
00620 (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec);
00621 #else
00622 struct timeval rawtime;
00623 gettimeofday(&rawtime, NULL);
00624 localtime_r (&rawtime.tv_sec, &timeinfo);
00625 int result = snprintf(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d.%s%d",
00626 timeinfo.tm_year+1900,
00627 (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
00628 (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
00629 (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
00630 (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
00631 (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec,
00632 (rawtime.tv_usec/1000) < 10 ? "00":(rawtime.tv_usec/1000) < 100?"0":"", int(rawtime.tv_usec/1000));
00633 #endif
00634 if(result)
00635 {
00636 timeStr.append(buf);
00637 }
00638 return result;
00639 }
00640
00641 ULogger* ULogger::getInstance()
00642 {
00643 if(!instance_)
00644 {
00645 instance_ = createInstance();
00646 }
00647 return instance_;
00648 }
00649
00650 ULogger* ULogger::createInstance()
00651 {
00652 ULogger* instance = 0;
00653 if(type_ == ULogger::kTypeConsole)
00654 {
00655 instance = new UConsoleLogger();
00656 }
00657 else if(type_ == ULogger::kTypeFile)
00658 {
00659 instance = new UFileLogger(logFileName_, append_);
00660 }
00661 destroyer_.setDoomed(instance);
00662 return instance;
00663 }
00664
00665 ULogger::~ULogger()
00666 {
00667 instance_ = 0;
00668
00669 }