ULogger.cpp
Go to the documentation of this file.
00001 /*
00002 *  utilite is a cross-platform library with
00003 *  useful utilities for fast and small developing.
00004 *  Copyright (C) 2010  Mathieu Labbe
00005 *
00006 *  utilite is free library: you can redistribute it and/or modify
00007 *  it under the terms of the GNU Lesser General Public License as published by
00008 *  the Free Software Foundation, either version 3 of the License, or
00009 *  (at your option) any later version.
00010 *
00011 *  utilite is distributed in the hope that it will be useful,
00012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 *  GNU Lesser General Public License for more details.
00015 *
00016 *  You should have received a copy of the GNU Lesser General Public License
00017 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
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; // By default, we show all info msgs + upper level (Warning, Error)
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; // Default nothing
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()); // TODO send Event instead, or return error code
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                 // instance not yet created
00182                 if(!instance_)
00183                 {
00184                         type_ = type;
00185                         logFileName_ = fileName;
00186                         append_ = append;
00187                         instance_ = createInstance();
00188                 }
00189                 // type changed
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; // By default, we show all info msgs + upper level (Warning, Error)
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                 // No need to show an empty message if we don't print where.
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                         //File
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                         //Line
00468                         whereStr.append(":");
00469                         std::string lineStr = uNumber2Str(line);
00470                         whereStr.append(lineStr);
00471 
00472                         //Function
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                                 // Send it synchronously, then receivers
00561                                 // can do something before the code (exiting) below is executed.
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_; // If a FileLogger is used, this will close the file.
00581                                 instance_ = 0;
00582                         }
00583                         //========================================================================
00584                         //                          Throw exception
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     //printf("Logger is destroyed...\n\r");
00669 }


rtabmap
Author(s): Mathieu Labbe
autogenerated on Thu Jun 6 2019 21:59:32