ULogger.cpp
Go to the documentation of this file.
1 /*
2 * utilite is a cross-platform library with
3 * useful utilities for fast and small developing.
4 * Copyright (C) 2010 Mathieu Labbe
5 *
6 * utilite is free library: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * utilite is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
22 #include "rtabmap/utilite/UFile.h"
23 #include "rtabmap/utilite/UStl.h"
25 #include <fstream>
26 #include <string>
27 #include <string.h>
28 
29 #ifndef _WIN32
30 #include <sys/time.h>
31 #endif
32 
33 #ifdef _WIN32
34 #include <Windows.h>
35 #define COLOR_NORMAL FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
36 #define COLOR_RED FOREGROUND_RED | FOREGROUND_INTENSITY
37 #define COLOR_GREEN FOREGROUND_GREEN
38 #define COLOR_YELLOW FOREGROUND_GREEN | FOREGROUND_RED
39 #else
40 #define COLOR_NORMAL "\033[0m"
41 #define COLOR_RED "\033[31m"
42 #define COLOR_GREEN "\033[32m"
43 #define COLOR_YELLOW "\033[33m"
44 #endif
45 
46 bool ULogger::append_ = true;
47 bool ULogger::printTime_ = true;
48 bool ULogger::printLevel_ = true;
49 bool ULogger::printEndline_ = true;
50 bool ULogger::printColored_ = true;
51 bool ULogger::printWhere_ = true;
52 bool ULogger::printWhereFullPath_ = false;
53 bool ULogger::printThreadID_ = false;
54 bool ULogger::limitWhereLength_ = false;
55 bool ULogger::buffered_ = false;
56 ULogger::Level ULogger::level_ = kInfo; // By default, we show all info msgs + upper level (Warning, Error)
58 const char * ULogger::levelName_[5] = {"DEBUG", " INFO", " WARN", "ERROR", "FATAL"};
63 const std::string ULogger::kDefaultLogFileName = "./ULog.txt";
64 std::string ULogger::logFileName_;
65 std::string ULogger::bufferedMsgs_;
66 std::set<unsigned long> ULogger::threadIdFilter_;
67 std::map<std::string, unsigned long> ULogger::registeredThreads_;
68 
75 class UConsoleLogger : public ULogger
76 {
77 public :
78  virtual ~UConsoleLogger() {this->_flush();}
79 
80 protected:
85  friend class ULogger;
86 
88 
89 private:
90  virtual void _write(const char* msg, va_list arg)
91  {
92  vprintf(msg, arg);
93  }
94  virtual void _writeStr(const char* msg)
95  {
96  printf("%s", msg);
97  }
98 };
99 
106 class UFileLogger : public ULogger
107 {
108 public:
109  virtual ~UFileLogger()
110  {
111  this->_flush();
112  if(fout_)
113  {
114  fclose(fout_);
115  }
116  }
117 
118 protected:
123  friend class ULogger;
124 
132  UFileLogger(const std::string &fileName, bool append)
133  {
134  fileName_ = fileName;
135 
136  if(!append) {
137  std::ofstream fileToClear(fileName_.c_str(), std::ios::out);
138  fileToClear.clear();
139  fileToClear.close();
140  }
141 
142 #ifdef _MSC_VER
143  fopen_s(&fout_, fileName_.c_str(), "a");
144 #else
145  fout_ = fopen(fileName_.c_str(), "a");
146 #endif
147 
148  if(!fout_) {
149  printf("FileLogger : Cannot open file : %s\n", fileName_.c_str()); // TODO send Event instead, or return error code
150  return;
151  }
152  }
153 
154 private:
155  virtual void _write(const char* msg, va_list arg)
156  {
157  if(fout_)
158  {
159  vfprintf(fout_, msg, arg);
160  }
161  }
162  virtual void _writeStr(const char* msg)
163  {
164  if(fout_)
165  {
166  fprintf(fout_, "%s", msg);
167  }
168  }
169 
170 private:
171  std::string fileName_;
172  FILE* fout_;
173  std::string bufferedMsgs_;
174 };
175 
176 void ULogger::setType(Type type, const std::string &fileName, bool append)
177 {
178  ULogger::flush();
179  loggerMutex_.lock();
180  {
181  // instance not yet created
182  if(!instance_)
183  {
184  type_ = type;
185  logFileName_ = fileName;
186  append_ = append;
188  }
189  // type changed
190  else if(type_ != type || (type_ == kTypeFile && logFileName_.compare(fileName)!=0))
191  {
193  delete instance_;
194  instance_ = 0;
195  type_ = type;
196  logFileName_ = fileName;
197  append_ = append;
199  }
200  }
202 }
203 
204 void ULogger::setTreadIdFilter(const std::vector<std::string> & ids)
205 {
206  loggerMutex_.lock();
207  threadIdFilter_.clear();
208  for(unsigned int i=0;i<ids.size();++i)
209  {
210  if(registeredThreads_.find(ids[i]) != registeredThreads_.end())
211  {
212  threadIdFilter_.insert(registeredThreads_.at(ids[i]));
213  }
214  }
216 }
217 
218 void ULogger::registerCurrentThread(const std::string & name)
219 {
220  loggerMutex_.lock();
221  UASSERT(!name.empty());
222  uInsert(registeredThreads_, std::make_pair(name, UThread::currentThreadId()));
224 }
225 
227 {
228  loggerMutex_.lock();
229 
230  unsigned long id = UThread::currentThreadId();
231  for(std::map<std::string, unsigned long>::iterator iter=registeredThreads_.begin(); iter!=registeredThreads_.end();)
232  {
233  if(iter->second == id)
234  {
235  registeredThreads_.erase(iter++);
236  threadIdFilter_.erase(id);
237  }
238  else
239  {
240  ++iter;
241  }
242  }
243 
245 }
246 
247 std::map<std::string, unsigned long> ULogger::getRegisteredThreads()
248 {
249  loggerMutex_.lock();
250  std::map<std::string, unsigned long> out = registeredThreads_;
252  return out;
253 }
254 
256 {
258  append_ = true;
259  printTime_ = true;
260  printLevel_ = true;
261  printEndline_ = true;
262  printColored_ = true;
263  printWhere_ = true;
264  printWhereFullPath_ = false;
265  printThreadID_ = false;
266  limitWhereLength_ = false;
267  level_ = kInfo; // By default, we show all info msgs + upper level (Warning, Error)
269 }
270 
271 void ULogger::setBuffered(bool buffered)
272 {
273  if(!buffered)
274  {
275  ULogger::flush();
276  }
277  buffered_ = buffered;
278 }
279 
280 
282 {
283  loggerMutex_.lock();
284  if(!instance_ || bufferedMsgs_.size()==0)
285  {
287  return;
288  }
289 
290  instance_->_flush();
292 }
293 
295 {
297  bufferedMsgs_.clear();
298 }
299 
300 void ULogger::write(const char* msg, ...)
301 {
302  loggerMutex_.lock();
303  if(!instance_)
304  {
306  return;
307  }
308 
309  std::string endline = "";
310  if(printEndline_) {
311  endline = "\r\n";
312  }
313 
314  std::string time = "";
315  if(printTime_)
316  {
317  getTime(time);
318  time.append(" - ");
319  }
320 
321 
322  if(printTime_)
323  {
324  if(buffered_)
325  {
326  bufferedMsgs_.append(time.c_str());
327  }
328  else
329  {
330  ULogger::getInstance()->_writeStr(time.c_str());
331  }
332  }
333 
334  va_list args;
335  va_start(args, msg);
336  if(buffered_)
337  {
338  bufferedMsgs_.append(uFormatv(msg, args));
339  }
340  else
341  {
342  ULogger::getInstance()->_write(msg, args);
343  }
344  va_end(args);
345  if(printEndline_)
346  {
347  if(buffered_)
348  {
349  bufferedMsgs_.append(endline.c_str());
350  }
351  else
352  {
353  ULogger::getInstance()->_writeStr(endline.c_str());
354  }
355  }
357 
358 }
359 
361  const char * file,
362  int line,
363  const char * function,
364  const char* msg,
365  ...)
366 {
367  loggerMutex_.lock();
368  if(type_ == kTypeNoLog && level < kFatal && level < eventLevel_)
369  {
371  return;
372  }
373  if(strlen(msg) == 0 && !printWhere_ && level < kFatal)
374  {
376  // No need to show an empty message if we don't print where.
377  return;
378  }
379  if(level < kFatal &&
380  threadIdFilter_.size() &&
382  {
384  return;
385  }
386 
387  if(level >= level_ || level >= eventLevel_)
388  {
389 #ifdef _WIN32
390  int color = 0;
391 #else
392  const char* color = NULL;
393 #endif
394  switch(level)
395  {
396  case kDebug:
397  color = COLOR_GREEN;
398  break;
399  case kInfo:
400  color = COLOR_NORMAL;
401  break;
402  case kWarning:
403  color = COLOR_YELLOW;
404  break;
405  case kError:
406  case kFatal:
407  color = COLOR_RED;
408  break;
409  default:
410  break;
411  }
412 
413  std::string endline = "";
414  if(printEndline_) {
415  endline = "\r\n";
416  }
417 
418  std::string time = "";
419  if(printTime_ || level == kFatal)
420  {
421  time.append("(");
422  getTime(time);
423  time.append(") ");
424  }
425 
426  std::string levelStr = "";
427  if(printLevel_ || level == kFatal)
428  {
429  const int bufSize = 30;
430  char buf[bufSize] = {0};
431 
432 #ifdef _MSC_VER
433  sprintf_s(buf, bufSize, "[%s]", levelName_[level]);
434 #else
435  snprintf(buf, bufSize, "[%s]", levelName_[level]);
436 #endif
437  levelStr = buf;
438  levelStr.append(" ");
439  }
440 
441  std::string pidStr;
442  if(printThreadID_)
443  {
444  pidStr = uFormat("{%lu} ", UThread::currentThreadId());
445  }
446 
447  std::string whereStr = "";
448  if(printWhere_ || level == kFatal)
449  {
450  whereStr.append("");
451  //File
453  {
454  whereStr.append(file);
455  }
456  else
457  {
458  std::string fileName = UFile::getName(file);
459  if(limitWhereLength_ && fileName.size() > 8)
460  {
461  fileName.erase(8);
462  fileName.append("~");
463  }
464  whereStr.append(fileName);
465  }
466 
467  //Line
468  whereStr.append(":");
469  std::string lineStr = uNumber2Str(line);
470  whereStr.append(lineStr);
471 
472  //Function
473  whereStr.append("::");
474  std::string funcStr = function;
475  if(!printWhereFullPath_ && limitWhereLength_ && funcStr.size() > 8)
476  {
477  funcStr.erase(8);
478  funcStr.append("~");
479  }
480  funcStr.append("()");
481  whereStr.append(funcStr);
482 
483  whereStr.append(" ");
484  }
485 
486  va_list args;
487 
488  if(type_ != kTypeNoLog)
489  {
490  va_start(args, msg);
491 #ifdef _WIN32
492  HANDLE H = GetStdHandle(STD_OUTPUT_HANDLE);
493 #endif
495  {
496 #ifdef _WIN32
497  SetConsoleTextAttribute(H,color);
498 #else
499  if(buffered_)
500  {
501  bufferedMsgs_.append(color);
502  }
503  else
504  {
506  }
507 #endif
508  }
509 
510  if(buffered_)
511  {
512  bufferedMsgs_.append(levelStr.c_str());
513  bufferedMsgs_.append(pidStr.c_str());
514  bufferedMsgs_.append(time.c_str());
515  bufferedMsgs_.append(whereStr.c_str());
516  bufferedMsgs_.append(uFormatv(msg, args));
517  }
518  else
519  {
520  ULogger::getInstance()->_writeStr(levelStr.c_str());
521  ULogger::getInstance()->_writeStr(pidStr.c_str());
522  ULogger::getInstance()->_writeStr(time.c_str());
523  ULogger::getInstance()->_writeStr(whereStr.c_str());
524  ULogger::getInstance()->_write(msg, args);
525  }
527  {
528 #ifdef _WIN32
529  SetConsoleTextAttribute(H,COLOR_NORMAL);
530 #else
531  if(buffered_)
532  {
533  bufferedMsgs_.append(COLOR_NORMAL);
534  }
535  else
536  {
538  }
539 #endif
540  }
541  if(buffered_)
542  {
543  bufferedMsgs_.append(endline.c_str());
544  }
545  else
546  {
547  ULogger::getInstance()->_writeStr(endline.c_str());
548  }
549  va_end (args);
550  }
551 
552  if(level >= eventLevel_)
553  {
554  std::string fullMsg = uFormat("%s%s%s%s", levelStr.c_str(), pidStr.c_str(), time.c_str(), whereStr.c_str());
555  va_start(args, msg);
556  fullMsg.append(uFormatv(msg, args));
557  va_end(args);
558  if(level >= kFatal)
559  {
560  // Send it synchronously, then receivers
561  // can do something before the code (exiting) below is executed.
562  UEventsManager::post(new ULogEvent(fullMsg, kFatal), false);
563  }
564  else
565  {
566  UEventsManager::post(new ULogEvent(fullMsg, level));
567  }
568  }
569 
570  if(level >= kFatal)
571  {
572  std::string fullMsg = uFormat("%s%s%s%s", levelStr.c_str(), pidStr.c_str(), time.c_str(), whereStr.c_str());
573  va_start(args, msg);
574  fullMsg.append(uFormatv(msg, args));
575  va_end(args);
576 
577  if(instance_)
578  {
580  delete instance_; // If a FileLogger is used, this will close the file.
581  instance_ = 0;
582  }
583  //========================================================================
584  // Throw exception
586  throw UException(fullMsg);
587  //========================================================================
588  }
589  }
591 }
592 
593 int ULogger::getTime(std::string &timeStr)
594 {
595  struct tm timeinfo;
596  const int bufSize = 30;
597  char buf[bufSize] = {0};
598 
599 #if _MSC_VER
600  time_t rawtime;
601  time(&rawtime);
602  localtime_s (&timeinfo, &rawtime );
603  int result = sprintf_s(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
604  timeinfo.tm_year+1900,
605  (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
606  (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
607  (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
608  (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
609  (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec);
610 #elif WIN32
611  time_t rawtime;
612  time(&rawtime);
613  timeinfo = *localtime (&rawtime);
614  int result = snprintf(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
615  timeinfo.tm_year+1900,
616  (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
617  (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
618  (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
619  (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
620  (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec);
621  #else
622  struct timeval rawtime;
623  gettimeofday(&rawtime, NULL);
624  localtime_r (&rawtime.tv_sec, &timeinfo);
625  int result = snprintf(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d.%s%d",
626  timeinfo.tm_year+1900,
627  (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
628  (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
629  (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
630  (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
631  (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec,
632  (rawtime.tv_usec/1000) < 10 ? "00":(rawtime.tv_usec/1000) < 100?"0":"", int(rawtime.tv_usec/1000));
633 #endif
634  if(result)
635  {
636  timeStr.append(buf);
637  }
638  return result;
639 }
640 
642 {
643  if(!instance_)
644  {
646  }
647  return instance_;
648 }
649 
651 {
652  ULogger* instance = 0;
654  {
655  instance = new UConsoleLogger();
656  }
657  else if(type_ == ULogger::kTypeFile)
658  {
659  instance = new UFileLogger(logFileName_, append_);
660  }
661  destroyer_.setDoomed(instance);
662  return instance;
663 }
664 
666 {
667  instance_ = 0;
668  //printf("Logger is destroyed...\n\r");
669 }
static Level eventLevel_
Definition: ULogger.h:554
#define NULL
#define COLOR_RED
Definition: ULogger.cpp:41
static bool buffered_
Definition: ULogger.h:567
#define COLOR_YELLOW
Definition: ULogger.cpp:43
static const std::string kDefaultLogFileName
Definition: ULogger.h:236
std::string getName()
Definition: UFile.h:135
static void post(UEvent *event, bool async=true, const UEventsSender *sender=0)
virtual ~UFileLogger()
Definition: ULogger.cpp:109
static std::map< std::string, unsigned long > registeredThreads_
Definition: ULogger.h:572
bool setDoomed(T *doomed)
Definition: UDestroyer.h:57
virtual void _writeStr(const char *msg)
Definition: ULogger.cpp:94
static std::map< std::string, unsigned long > getRegisteredThreads()
Definition: ULogger.cpp:247
void _flush()
Definition: ULogger.cpp:294
static std::string bufferedMsgs_
Definition: ULogger.h:569
static void unregisterCurrentThread()
Definition: ULogger.cpp:226
static bool printThreadID_
Definition: ULogger.h:531
static ULogger * createInstance()
Definition: ULogger.cpp:650
static bool printEndline_
Definition: ULogger.h:505
static bool limitWhereLength_
Definition: ULogger.h:539
static void reset()
Definition: ULogger.cpp:255
static ULogger * instance_
Definition: ULogger.h:482
Some conversion functions.
static void setTreadIdFilter(const std::set< unsigned long > &ids)
Definition: ULogger.h:354
static Level level_
Definition: ULogger.h:549
static bool printLevel_
Definition: ULogger.h:499
static void setBuffered(bool buffered)
Definition: ULogger.cpp:271
FILE * fout_
Definition: ULogger.cpp:172
#define UASSERT(condition)
Wrappers of STL for convenient functions.
int lock() const
Definition: UMutex.h:87
virtual void _writeStr(const char *)
Definition: ULogger.h:476
static bool printWhereFullPath_
Definition: ULogger.h:525
virtual ~ULogger()
Definition: ULogger.cpp:665
static Type type()
Definition: ULogger.h:266
Definition: UMutex.h:54
static ULogger * getInstance()
Definition: ULogger.cpp:641
static const char * levelName_[5]
Definition: ULogger.h:556
static void registerCurrentThread(const std::string &name)
Definition: ULogger.cpp:218
static void setType(Type type, const std::string &fileName=kDefaultLogFileName, bool append=true)
Definition: ULogger.cpp:176
static int getTime(std::string &timeStr)
Definition: ULogger.cpp:593
static void write(const char *msg,...)
Definition: ULogger.cpp:300
int unlock() const
Definition: UMutex.h:113
std::string UTILITE_EXP uFormatv(const char *fmt, va_list ap)
static std::string logFileName_
Definition: ULogger.h:451
virtual void _writeStr(const char *msg)
Definition: ULogger.cpp:162
static bool printColored_
Definition: ULogger.h:511
static ULogger::Level level()
Definition: ULogger.h:340
virtual ~UConsoleLogger()
Definition: ULogger.cpp:78
std::string bufferedMsgs_
Definition: ULogger.cpp:173
virtual void _write(const char *, va_list)
Definition: ULogger.h:475
static bool append_
Definition: ULogger.h:456
ULogger class and convenient macros.
#define COLOR_NORMAL
Definition: ULogger.cpp:40
static bool printWhere_
Definition: ULogger.h:517
std::string fileName_
the file name
Definition: ULogger.cpp:171
static bool printTime_
Definition: ULogger.h:493
static void flush()
Definition: ULogger.cpp:281
static Type type_
Definition: ULogger.h:544
static UDestroyer< ULogger > destroyer_
Definition: ULogger.h:487
static std::set< unsigned long > threadIdFilter_
Definition: ULogger.h:571
std::string UTILITE_EXP uFormat(const char *fmt,...)
std::string UTILITE_EXP uNumber2Str(unsigned int number)
Definition: UConversion.cpp:91
#define COLOR_GREEN
Definition: ULogger.cpp:42
UFileLogger(const std::string &fileName, bool append)
Definition: ULogger.cpp:132
static UMutex loggerMutex_
Definition: ULogger.h:561
void uInsert(std::map< K, V > &map, const std::pair< K, V > &pair)
Definition: UStl.h:443
static unsigned long currentThreadId()
Definition: UThread.h:96
virtual void _write(const char *msg, va_list arg)
Definition: ULogger.cpp:90
virtual void _write(const char *msg, va_list arg)
Definition: ULogger.cpp:155


rtabmap
Author(s): Mathieu Labbe
autogenerated on Mon Jan 23 2023 03:38:58