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 
21 
22 #include "utilite/UConversion.h"
23 #include "utilite/UFile.h"
24 #include "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::limitWhereLength_ = false;
54 bool ULogger::buffered_ = false;
55 bool ULogger::exitingState_ = false;
59 const char * ULogger::levelName_[5] = {"DEBUG", " INFO", " WARN", "ERROR", "FATAL"};
64 const std::string ULogger::kDefaultLogFileName = "./ULog.txt";
65 std::string ULogger::logFileName_;
66 std::string ULogger::bufferedMsgs_;
67 
74 class UConsoleLogger : public ULogger
75 {
76 public :
77  virtual ~UConsoleLogger() {this->_flush();}
78 
79 protected:
84  friend class ULogger;
85 
87 
88 private:
89  virtual void _write(const char* msg, va_list arg)
90  {
91  vprintf(msg, arg);
92  }
93  virtual void _writeStr(const char* msg)
94  {
95  printf("%s", msg);
96  }
97 };
98 
105 class UFileLogger : public ULogger
106 {
107 public:
108  virtual ~UFileLogger()
109  {
110  this->_flush();
111  if(fout_)
112  {
113  fclose(fout_);
114  }
115  }
116 
117 protected:
122  friend class ULogger;
123 
131  UFileLogger(const std::string &fileName, bool append)
132  {
133  fileName_ = fileName;
134 
135  if(!append) {
136  std::ofstream fileToClear(fileName_.c_str(), std::ios::out);
137  fileToClear.clear();
138  fileToClear.close();
139  }
140 
141 #ifdef _MSC_VER
142  fopen_s(&fout_, fileName_.c_str(), "a");
143 #else
144  fout_ = fopen(fileName_.c_str(), "a");
145 #endif
146 
147  if(!fout_) {
148  printf("FileLogger : Cannot open file : %s\n", fileName_.c_str()); // TODO send Event instead, or return error code
149  return;
150  }
151  }
152 
153 private:
154  virtual void _write(const char* msg, va_list arg)
155  {
156  if(fout_)
157  {
158  vfprintf(fout_, msg, arg);
159  }
160  }
161  virtual void _writeStr(const char* msg)
162  {
163  if(fout_)
164  {
165  fprintf(fout_, "%s", msg);
166  }
167  }
168 
169 private:
170  std::string fileName_;
171  FILE* fout_;
172  std::string bufferedMsgs_;
173 };
174 
175 void ULogger::setType(Type type, const std::string &fileName, bool append)
176 {
177  ULogger::flush();
178  loggerMutex_.lock();
179  {
180  // instance not yet created
181  if(!instance_)
182  {
183  type_ = type;
184  logFileName_ = fileName;
185  append_ = append;
187  }
188  // type changed
189  else if(type_ != type || (type_ == kTypeFile && logFileName_.compare(fileName)!=0))
190  {
192  delete instance_;
193  instance_ = 0;
194  type_ = type;
195  logFileName_ = fileName;
196  append_ = append;
198  }
199  }
201 }
202 
204 {
206  append_ = true;
207  printTime_ = true;
208  printLevel_ = true;
209  printEndline_ = true;
210  printColored_ = true;
211  printWhere_ = true;
212  printWhereFullPath_ = false;
213  limitWhereLength_ = false;
214  level_ = kInfo; // By default, we show all info msgs + upper level (Warning, Error)
216 }
217 
218 void ULogger::setBuffered(bool buffered)
219 {
220  if(!buffered)
221  {
222  ULogger::flush();
223  }
224  buffered_ = buffered;
225 }
226 
227 
229 {
230  loggerMutex_.lock();
231  if(!instance_ || bufferedMsgs_.size()==0)
232  {
234  return;
235  }
236 
237  instance_->_flush();
239 }
240 
242 {
244  bufferedMsgs_.clear();
245 }
246 
247 void ULogger::write(const char* msg, ...)
248 {
249  loggerMutex_.lock();
250  if(!instance_)
251  {
253  return;
254  }
255 
256  std::string endline = "";
257  if(printEndline_) {
258  endline = "\r\n";
259  }
260 
261  std::string time = "";
262  if(printTime_)
263  {
264  getTime(time);
265  time.append(" - ");
266  }
267 
268 
269  if(printTime_)
270  {
271  if(buffered_)
272  {
273  bufferedMsgs_.append(time.c_str());
274  }
275  else
276  {
277  ULogger::getInstance()->_writeStr(time.c_str());
278  }
279  }
280 
281  va_list args;
282  va_start(args, msg);
283  if(buffered_)
284  {
285  bufferedMsgs_.append(uFormatv(msg, args));
286  }
287  else
288  {
289  ULogger::getInstance()->_write(msg, args);
290  }
291  va_end(args);
292  if(printEndline_)
293  {
294  if(buffered_)
295  {
296  bufferedMsgs_.append(endline.c_str());
297  }
298  else
299  {
300  ULogger::getInstance()->_writeStr(endline.c_str());
301  }
302  }
304 
305 }
306 
308  const char * file,
309  int line,
310  const char * function,
311  const char* msg,
312  ...)
313 {
314  if(exitingState_)
315  {
316  // Ignore messages after a fatal exit...
317  return;
318  }
319  loggerMutex_.lock();
320  if(type_ == kTypeNoLog && level < kFatal)
321  {
323  return;
324  }
325  if(strlen(msg) == 0 && !printWhere_ && level < exitLevel_)
326  {
328  // No need to show an empty message if we don't print where.
329  return;
330  }
331 
332  if(level >= level_)
333  {
334 #ifdef WIN32
335  int color = 0;
336 #else
337  const char* color = NULL;
338 #endif
339  switch(level)
340  {
341  case kDebug:
342  color = COLOR_GREEN;
343  break;
344  case kInfo:
345  color = COLOR_NORMAL;
346  break;
347  case kWarning:
348  color = COLOR_YELLOW;
349  break;
350  case kError:
351  case kFatal:
352  color = COLOR_RED;
353  break;
354  default:
355  break;
356  }
357 
358  std::string endline = "";
359  if(printEndline_) {
360  endline = "\r\n";
361  }
362 
363  std::string time = "";
364  if(printTime_)
365  {
366  time.append("(");
367  getTime(time);
368  time.append(") ");
369  }
370 
371  std::string levelStr = "";
372  if(printLevel_)
373  {
374  const int bufSize = 30;
375  char buf[bufSize] = {0};
376 
377 #ifdef _MSC_VER
378  sprintf_s(buf, bufSize, "[%s]", levelName_[level]);
379 #else
380  snprintf(buf, bufSize, "[%s]", levelName_[level]);
381 #endif
382  levelStr = buf;
383  levelStr.append(" ");
384  }
385 
386  std::string whereStr = "";
387  if(printWhere_)
388  {
389  whereStr.append("");
390  //File
392  {
393  whereStr.append(file);
394  }
395  else
396  {
397  std::string fileName = UFile::getName(file);
398  if(limitWhereLength_ && fileName.size() > 8)
399  {
400  fileName.erase(8);
401  fileName.append("~");
402  }
403  whereStr.append(fileName);
404  }
405 
406  //Line
407  whereStr.append(":");
408  std::string lineStr = uNumber2Str(line);
409  whereStr.append(lineStr);
410 
411  //Function
412  whereStr.append("::");
413  std::string funcStr = function;
414  if(!printWhereFullPath_ && limitWhereLength_ && funcStr.size() > 8)
415  {
416  funcStr.erase(8);
417  funcStr.append("~");
418  }
419  funcStr.append("()");
420  whereStr.append(funcStr);
421 
422  whereStr.append(" ");
423  }
424 
425  va_list args;
426 
427  if(type_ != kTypeNoLog)
428  {
429  va_start(args, msg);
430 #ifdef WIN32
431  HANDLE H = GetStdHandle(STD_OUTPUT_HANDLE);
432 #endif
434  {
435 #ifdef WIN32
436  SetConsoleTextAttribute(H,color);
437 #else
438  if(buffered_)
439  {
440  bufferedMsgs_.append(color);
441  }
442  else
443  {
445  }
446 #endif
447  }
448 
449  if(buffered_)
450  {
451  bufferedMsgs_.append(levelStr.c_str());
452  bufferedMsgs_.append(time.c_str());
453  bufferedMsgs_.append(whereStr.c_str());
454  bufferedMsgs_.append(uFormatv(msg, args));
455  }
456  else
457  {
458  ULogger::getInstance()->_writeStr(levelStr.c_str());
459  ULogger::getInstance()->_writeStr(time.c_str());
460  ULogger::getInstance()->_writeStr(whereStr.c_str());
461  ULogger::getInstance()->_write(msg, args);
462  }
464  {
465 #ifdef WIN32
466  SetConsoleTextAttribute(H,COLOR_NORMAL);
467 #else
468  if(buffered_)
469  {
470  bufferedMsgs_.append(COLOR_NORMAL);
471  }
472  else
473  {
475  }
476 #endif
477  }
478  if(buffered_)
479  {
480  bufferedMsgs_.append(endline.c_str());
481  }
482  else
483  {
484  ULogger::getInstance()->_writeStr(endline.c_str());
485  }
486  va_end (args);
487  }
488 
489  if(level >= exitLevel_)
490  {
491  printf("\n*******\n%s message occurred! Application will now exit.\n", levelName_[level]);
492  if(type_ != kTypeConsole)
493  {
494  printf(" %s%s%s\n", levelStr.c_str(), time.c_str(), whereStr.c_str());
495  va_start(args, msg);
496  vprintf(msg, args);
497  va_end(args);
498  }
499  printf("*******\n");
501  delete instance_; // If a FileLogger is used, this will close the file.
502  instance_ = 0;
503  //========================================================================
504  // EXIT APPLICATION
505  exit(1);
506  //========================================================================
507  }
508  }
510 }
511 
512 int ULogger::getTime(std::string &timeStr)
513 {
514  if(!printTime_) {
515  return 0;
516  }
517  struct tm timeinfo;
518  const int bufSize = 30;
519  char buf[bufSize] = {0};
520 
521 #if _MSC_VER
522  time_t rawtime;
523  time(&rawtime);
524  localtime_s (&timeinfo, &rawtime );
525  int result = sprintf_s(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
526  timeinfo.tm_year+1900,
527  (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
528  (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
529  (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
530  (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
531  (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec);
532 #elif WIN32
533  time_t rawtime;
534  time(&rawtime);
535  timeinfo = *localtime (&rawtime);
536  int result = snprintf(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d",
537  timeinfo.tm_year+1900,
538  (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
539  (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
540  (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
541  (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
542  (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec);
543  #else
544  struct timeval rawtime;
545  gettimeofday(&rawtime, NULL);
546  localtime_r (&rawtime.tv_sec, &timeinfo);
547  int result = snprintf(buf, bufSize, "%d-%s%d-%s%d %s%d:%s%d:%s%d.%s%d",
548  timeinfo.tm_year+1900,
549  (timeinfo.tm_mon+1) < 10 ? "0":"", timeinfo.tm_mon+1,
550  (timeinfo.tm_mday) < 10 ? "0":"", timeinfo.tm_mday,
551  (timeinfo.tm_hour) < 10 ? "0":"", timeinfo.tm_hour,
552  (timeinfo.tm_min) < 10 ? "0":"", timeinfo.tm_min,
553  (timeinfo.tm_sec) < 10 ? "0":"", timeinfo.tm_sec,
554  (rawtime.tv_usec/1000) < 10 ? "00":(rawtime.tv_usec/1000) < 100?"0":"", int(rawtime.tv_usec/1000));
555 #endif
556  if(result)
557  {
558  timeStr.append(buf);
559  }
560  return result;
561 }
562 
564 {
565  if(!instance_)
566  {
568  }
569  return instance_;
570 }
571 
573 {
574  ULogger* instance = 0;
576  {
577  instance = new UConsoleLogger();
578  }
579  else if(type_ == ULogger::kTypeFile)
580  {
581  instance = new UFileLogger(logFileName_, append_);
582  }
583  destroyer_.setDoomed(instance);
584  return instance;
585 }
586 
588 {
589  instance_ = 0;
590  //printf("Logger is destroyed...\n\r");
591 }
static Level eventLevel_
Definition: ULogger.h:510
#define COLOR_RED
Definition: ULogger.cpp:41
static bool buffered_
Definition: ULogger.h:523
#define COLOR_YELLOW
Definition: ULogger.cpp:43
static const std::string kDefaultLogFileName
Definition: ULogger.h:205
std::string getName()
Definition: UFile.h:126
virtual ~UFileLogger()
Definition: ULogger.cpp:108
bool setDoomed(T *doomed)
Definition: UDestroyer.h:57
virtual void _writeStr(const char *msg)
Definition: ULogger.cpp:93
void _flush()
Definition: ULogger.cpp:241
virtual void _writeStr(const char *msg)
Definition: ULogger.h:432
static std::string bufferedMsgs_
Definition: ULogger.h:525
static ULogger * createInstance()
Definition: ULogger.cpp:572
static bool printEndline_
Definition: ULogger.h:461
static bool limitWhereLength_
Definition: ULogger.h:489
static void reset()
Definition: ULogger.cpp:203
static ULogger * instance_
Definition: ULogger.h:438
Some conversion functions.
static Level level_
Definition: ULogger.h:499
static bool printLevel_
Definition: ULogger.h:455
static void setBuffered(bool buffered)
Definition: ULogger.cpp:218
FILE * fout_
Definition: ULogger.cpp:171
Wrappers of STL for convenient functions.
int lock() const
Definition: UMutex.h:87
static Level exitLevel_
Definition: ULogger.h:505
std::string uNumber2Str(unsigned int number)
Definition: UConversion.cpp:89
static bool printWhereFullPath_
Definition: ULogger.h:481
virtual ~ULogger()
Definition: ULogger.cpp:587
static Type type()
Definition: ULogger.h:235
Definition: UMutex.h:54
static ULogger * getInstance()
Definition: ULogger.cpp:563
static const char * levelName_[5]
Definition: ULogger.h:512
static void setType(Type type, const std::string &fileName=kDefaultLogFileName, bool append=true)
Definition: ULogger.cpp:175
static int getTime(std::string &timeStr)
Definition: ULogger.cpp:512
static void write(const char *msg,...)
Definition: ULogger.cpp:247
static bool exitingState_
Definition: ULogger.h:533
int unlock() const
Definition: UMutex.h:113
static std::string logFileName_
Definition: ULogger.h:407
virtual void _writeStr(const char *msg)
Definition: ULogger.cpp:161
static bool printColored_
Definition: ULogger.h:467
static ULogger::Level level()
Definition: ULogger.h:302
virtual ~UConsoleLogger()
Definition: ULogger.cpp:77
std::string bufferedMsgs_
Definition: ULogger.cpp:172
static bool append_
Definition: ULogger.h:412
ULogger class and convenient macros.
#define COLOR_NORMAL
Definition: ULogger.cpp:40
static bool printWhere_
Definition: ULogger.h:473
std::string fileName_
the file name
Definition: ULogger.cpp:170
static bool printTime_
Definition: ULogger.h:449
static void flush()
Definition: ULogger.cpp:228
static Type type_
Definition: ULogger.h:494
static UDestroyer< ULogger > destroyer_
Definition: ULogger.h:443
std::string uFormatv(const char *fmt, va_list args)
#define COLOR_GREEN
Definition: ULogger.cpp:42
UFileLogger(const std::string &fileName, bool append)
Definition: ULogger.cpp:131
static UMutex loggerMutex_
Definition: ULogger.h:517
virtual void _write(const char *msg, va_list arg)
Definition: ULogger.h:431
virtual void _write(const char *msg, va_list arg)
Definition: ULogger.cpp:89
virtual void _write(const char *msg, va_list arg)
Definition: ULogger.cpp:154


find_object_2d
Author(s): Mathieu Labbe
autogenerated on Mon Dec 12 2022 03:20:10