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 
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()); // TODO send Event instead, or return error code
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                 // instance not yet created
00180                 if(!instance_)
00181                 {
00182                         type_ = type;
00183                         logFileName_ = fileName;
00184                         append_ = append;
00185                         instance_ = createInstance();
00186                 }
00187                 // type changed
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; // 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         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                 // No need to show an empty message if we don't print where.
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                         //File
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                         //Line
00408                         whereStr.append(":");
00409                         std::string lineStr = uNumber2Str(line);
00410                         whereStr.append(lineStr);
00411 
00412                         //Function
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                                 // Send it synchronously, then receivers
00501                                 // can do something before the code (exiting) below is executed.
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_; // If a FileLogger is used, this will close the file.
00521                                 instance_ = 0;
00522                         }
00523                         //========================================================================
00524                         //                          Throw exception
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     //printf("Logger is destroyed...\n\r");
00609 }


rtabmap
Author(s): Mathieu Labbe
autogenerated on Sat Jul 23 2016 11:44:28