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::limitWhereLength_ = false;
00054 bool ULogger::buffered_ = false;
00055 bool ULogger::exitingState_ = false;
00056 ULogger::Level ULogger::level_ = kInfo; // By default, we show all info msgs + upper level (Warning, Error)
00057 ULogger::Level ULogger::exitLevel_ = kFatal;
00058 ULogger::Level ULogger::eventLevel_ = kFatal;
00059 const char * ULogger::levelName_[5] = {"DEBUG", " INFO", " WARN", "ERROR", "FATAL"};
00060 ULogger* ULogger::instance_ = 0;
00061 UDestroyer<ULogger> ULogger::destroyer_;
00062 ULogger::Type ULogger::type_ = ULogger::kTypeNoLog; // Default nothing
00063 UMutex ULogger::loggerMutex_;
00064 const std::string ULogger::kDefaultLogFileName = "./ULog.txt";
00065 std::string ULogger::logFileName_;
00066 std::string ULogger::bufferedMsgs_;
00067 
00074 class UConsoleLogger : public ULogger
00075 {
00076 public :
00077     virtual ~UConsoleLogger() {this->_flush();}
00078 
00079 protected:
00084     friend class ULogger;
00085 
00086     UConsoleLogger() {}
00087 
00088 private:
00089     virtual void _write(const char* msg, va_list arg)
00090     {
00091                 vprintf(msg, arg);
00092     }
00093     virtual void _writeStr(const char* msg)
00094         {
00095                 printf("%s", msg);
00096         }
00097 };
00098 
00105 class UFileLogger : public ULogger
00106 {
00107 public:
00108     virtual ~UFileLogger()
00109     {
00110         this->_flush();
00111         if(fout_)
00112         {
00113                 fclose(fout_);
00114         }
00115     }
00116 
00117 protected:
00122     friend class ULogger;
00123 
00131     UFileLogger(const std::string &fileName, bool append)
00132     {
00133         fileName_ = fileName;
00134 
00135         if(!append) {
00136                         std::ofstream fileToClear(fileName_.c_str(), std::ios::out);
00137                         fileToClear.clear();
00138                         fileToClear.close();
00139                 }
00140 
00141 #ifdef _MSC_VER
00142         fopen_s(&fout_, fileName_.c_str(), "a");
00143 #else
00144         fout_ = fopen(fileName_.c_str(), "a");
00145 #endif
00146 
00147         if(!fout_) {
00148             printf("FileLogger : Cannot open file : %s\n", fileName_.c_str()); // TODO send Event instead, or return error code
00149             return;
00150         }
00151     }
00152 
00153 private:
00154     virtual void _write(const char* msg, va_list arg)
00155     {
00156         if(fout_)
00157         {
00158                 vfprintf(fout_, msg, arg);
00159         }
00160     }
00161     virtual void _writeStr(const char* msg)
00162         {
00163                 if(fout_)
00164                 {
00165                         fprintf(fout_, "%s", msg);
00166                 }
00167         }
00168 
00169 private:
00170     std::string fileName_; 
00171     FILE* fout_;
00172     std::string bufferedMsgs_;
00173 };
00174 
00175 void ULogger::setType(Type type, const std::string &fileName, bool append)
00176 {
00177         ULogger::flush();
00178     loggerMutex_.lock();
00179     {
00180                 // instance not yet created
00181                 if(!instance_)
00182                 {
00183                         type_ = type;
00184                         logFileName_ = fileName;
00185                         append_ = append;
00186                         instance_ = createInstance();
00187                 }
00188                 // type changed
00189                 else if(type_ != type || (type_ == kTypeFile && logFileName_.compare(fileName)!=0))
00190                 {
00191                         destroyer_.setDoomed(0);
00192                         delete instance_;
00193                         instance_ = 0;
00194                         type_ = type;
00195                         logFileName_ = fileName;
00196                         append_ = append;
00197                         instance_ = createInstance();
00198                 }
00199     }
00200     loggerMutex_.unlock();
00201 }
00202 
00203 void ULogger::reset()
00204 {
00205         ULogger::setType(ULogger::kTypeNoLog);
00206         append_ = true;
00207         printTime_ = true;
00208         printLevel_ = true;
00209         printEndline_ = true;
00210         printColored_ = true;
00211         printWhere_ = true;
00212         printWhereFullPath_ = false;
00213         limitWhereLength_ = false;
00214         level_ = kInfo; // By default, we show all info msgs + upper level (Warning, Error)
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         if(exitingState_)
00315         {
00316                 // Ignore messages after a fatal exit...
00317                 return;
00318         }
00319         loggerMutex_.lock();
00320         if(type_ == kTypeNoLog && level < kFatal)
00321         {
00322                 loggerMutex_.unlock();
00323                 return;
00324         }
00325         if(strlen(msg) == 0 && !printWhere_ && level < exitLevel_)
00326         {
00327                 loggerMutex_.unlock();
00328                 // No need to show an empty message if we don't print where.
00329                 return;
00330         }
00331 
00332     if(level >= level_)
00333     {
00334 #ifdef _WIN32
00335         int color = 0;
00336 #else
00337         const char* color = NULL;
00338 #endif
00339         switch(level)
00340         {
00341         case kDebug:
00342                 color = COLOR_GREEN;
00343                 break;
00344         case kInfo:
00345                 color = COLOR_NORMAL;
00346                 break;
00347         case kWarning:
00348                 color = COLOR_YELLOW;
00349                 break;
00350         case kError:
00351         case kFatal:
00352                 color = COLOR_RED;
00353                 break;
00354         default:
00355                 break;
00356         }
00357 
00358                 std::string endline = "";
00359                 if(printEndline_) {
00360                         endline = "\r\n";
00361                 }
00362 
00363                 std::string time = "";
00364                 if(printTime_ || level == kFatal)
00365                 {
00366                         time.append("(");
00367                         getTime(time);
00368                         time.append(") ");
00369                 }
00370 
00371                 std::string levelStr = "";
00372                 if(printLevel_ || level == kFatal)
00373                 {
00374                         const int bufSize = 30;
00375                         char buf[bufSize] = {0};
00376 
00377 #ifdef _MSC_VER
00378                         sprintf_s(buf, bufSize, "[%s]", levelName_[level]);
00379 #else
00380                         snprintf(buf, bufSize, "[%s]", levelName_[level]);
00381 #endif
00382                         levelStr = buf;
00383                         levelStr.append(" ");
00384                 }
00385 
00386                 std::string whereStr = "";
00387                 if(printWhere_ || level == kFatal)
00388                 {
00389                         whereStr.append("");
00390                         //File
00391                         if(printWhereFullPath_)
00392                         {
00393                                 whereStr.append(file);
00394                         }
00395                         else
00396                         {
00397                                 std::string fileName = UFile::getName(file);
00398                                 if(limitWhereLength_ && fileName.size() > 8)
00399                                 {
00400                                         fileName.erase(8);
00401                                         fileName.append("~");
00402                                 }
00403                                 whereStr.append(fileName);
00404                         }
00405 
00406                         //Line
00407                         whereStr.append(":");
00408                         std::string lineStr = uNumber2Str(line);
00409                         whereStr.append(lineStr);
00410 
00411                         //Function
00412                         whereStr.append("::");
00413                         std::string funcStr = function;
00414                         if(!printWhereFullPath_ && limitWhereLength_ && funcStr.size() > 8)
00415                         {
00416                                 funcStr.erase(8);
00417                                 funcStr.append("~");
00418                         }
00419                         funcStr.append("()");
00420                         whereStr.append(funcStr);
00421 
00422                         whereStr.append(" ");
00423                 }
00424 
00425                 va_list args;
00426 
00427                 if(type_ != kTypeNoLog)
00428                 {
00429                         va_start(args, msg);
00430 #ifdef _WIN32
00431                         HANDLE H = GetStdHandle(STD_OUTPUT_HANDLE);
00432 #endif
00433                         if(type_ == ULogger::kTypeConsole && printColored_)
00434                         {
00435 #ifdef _WIN32
00436                                 SetConsoleTextAttribute(H,color);
00437 #else
00438                                 if(buffered_)
00439                                 {
00440                                         bufferedMsgs_.append(color);
00441                                 }
00442                                 else
00443                                 {
00444                                         ULogger::getInstance()->_writeStr(color);
00445                                 }
00446 #endif
00447                         }
00448 
00449                         if(buffered_)
00450                         {
00451                                 bufferedMsgs_.append(levelStr.c_str());
00452                                 bufferedMsgs_.append(time.c_str());
00453                                 bufferedMsgs_.append(whereStr.c_str());
00454                                 bufferedMsgs_.append(uFormatv(msg, args));
00455                         }
00456                         else
00457                         {
00458                                 ULogger::getInstance()->_writeStr(levelStr.c_str());
00459                                 ULogger::getInstance()->_writeStr(time.c_str());
00460                                 ULogger::getInstance()->_writeStr(whereStr.c_str());
00461                                 ULogger::getInstance()->_write(msg, args);
00462                         }
00463                         if(type_ == ULogger::kTypeConsole && printColored_)
00464                         {
00465 #ifdef _WIN32
00466                                 SetConsoleTextAttribute(H,COLOR_NORMAL);
00467 #else
00468                                 if(buffered_)
00469                                 {
00470                                         bufferedMsgs_.append(COLOR_NORMAL);
00471                                 }
00472                                 else
00473                                 {
00474                                         ULogger::getInstance()->_writeStr(COLOR_NORMAL);
00475                                 }
00476 #endif
00477                         }
00478                         if(buffered_)
00479                         {
00480                                 bufferedMsgs_.append(endline.c_str());
00481                         }
00482                         else
00483                         {
00484                                 ULogger::getInstance()->_writeStr(endline.c_str());
00485                         }
00486                         va_end (args);
00487                 }
00488 
00489                 if(level >= eventLevel_)
00490                 {
00491                         std::string fullMsg = uFormat("%s%s%s", levelStr.c_str(), time.c_str(), whereStr.c_str());
00492                         va_start(args, msg);
00493                         fullMsg.append(uFormatv(msg, args));
00494                         va_end(args);
00495                         if(level >= exitLevel_)
00496                         {
00497                                 // Send it synchronously, then receivers
00498                                 // can do something before the code (exiting) below is executed.
00499                                 exitingState_ = true;
00500                                 UEventsManager::post(new ULogEvent(fullMsg, kFatal), false);
00501                         }
00502                         else
00503                         {
00504                                 UEventsManager::post(new ULogEvent(fullMsg, level));
00505                         }
00506                 }
00507 
00508                 if(level >= exitLevel_)
00509                 {
00510                         printf("\n*******\n%s message occurred! Application will now exit.\n", levelName_[level]);
00511                         if(type_ != kTypeConsole)
00512                         {
00513                                 printf("  %s%s%s", levelStr.c_str(), time.c_str(), whereStr.c_str());
00514                                 va_start(args, msg);
00515                                 vprintf(msg, args);
00516                                 va_end(args);
00517                         }
00518                         printf("\n*******\n");
00519                         destroyer_.setDoomed(0);
00520                         delete instance_; // If a FileLogger is used, this will close the file.
00521                         instance_ = 0;
00522                         //========================================================================
00523                         //                          EXIT APPLICATION
00524                         exit(1);
00525                         //========================================================================
00526                 }
00527     }
00528     loggerMutex_.unlock();
00529 }
00530 
00531 int ULogger::getTime(std::string &timeStr)
00532 {
00533     struct tm timeinfo;
00534     const int bufSize = 30;
00535     char buf[bufSize] = {0};
00536 
00537 #if _MSC_VER
00538     time_t rawtime;
00539     time(&rawtime);
00540     localtime_s (&timeinfo, &rawtime );
00541     int result = sprintf_s(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
00542         timeinfo.tm_year+1900,
00543         (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
00544         (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
00545         (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
00546         (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
00547         (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec);
00548 #elif WIN32
00549     time_t rawtime;
00550     time(&rawtime);
00551     timeinfo = *localtime (&rawtime);
00552     int result = snprintf(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
00553                 timeinfo.tm_year+1900,
00554                 (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
00555                 (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
00556                 (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
00557                 (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
00558                 (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec);
00559  #else
00560     struct timeval rawtime;
00561     gettimeofday(&rawtime, NULL);
00562     localtime_r (&rawtime.tv_sec, &timeinfo);
00563         int result = snprintf(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d.%s%d",
00564                 timeinfo.tm_year+1900,
00565                 (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
00566                 (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
00567                 (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
00568                 (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
00569                 (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec,
00570             (rawtime.tv_usec/1000) < 10 ? "00":(rawtime.tv_usec/1000) < 100?"0":"", int(rawtime.tv_usec/1000));
00571 #endif
00572     if(result)
00573     {
00574         timeStr.append(buf);
00575     }
00576     return result;
00577 }
00578 
00579 ULogger* ULogger::getInstance()
00580 {
00581         if(!instance_)
00582         {
00583                 instance_ = createInstance();
00584         }
00585     return instance_;
00586 }
00587 
00588 ULogger* ULogger::createInstance()
00589 {
00590     ULogger* instance = 0;
00591     if(type_ == ULogger::kTypeConsole)
00592     {
00593         instance = new UConsoleLogger();
00594     }
00595     else if(type_ == ULogger::kTypeFile)
00596     {
00597         instance = new UFileLogger(logFileName_, append_);
00598     }
00599     destroyer_.setDoomed(instance);
00600     return instance;
00601 }
00602 
00603 ULogger::~ULogger() 
00604 {
00605     instance_ = 0;
00606     //printf("Logger is destroyed...\n\r");
00607 }


rtabmap
Author(s): Mathieu Labbe
autogenerated on Fri Aug 28 2015 12:51:42