Scarab  v3.5.4
Project 8 C++ Utility Library
logger.cc
Go to the documentation of this file.
1 /*
2  * logger.cxx
3  * based on KLogger.cxx from KATRIN's Kasper
4  *
5  * Created on: 18.11.2011
6  * Author: Marco Haag <marco.haag@kit.edu>
7  */
8 
9 #define SCARAB_API_EXPORTS
10 
11 
12 #include <algorithm>
13 #include <cstring> // for strrchr
14 #include <iomanip>
15 #include <iterator>
16 #include <mutex>
17 #include <set>
18 #include <time.h>
19 
20 #ifndef NDEBUG
21 #include <thread>
22 #endif
23 
24 #include "logger.hh"
25 
26 using namespace std;
27 
28 namespace scarab
29 {
30  const string& EndColor() {static string* color = new string(COLOR_PREFIX COLOR_NORMAL COLOR_SUFFIX); return *color;}
31  const string& FatalColor() {static string* color = new string(COLOR_PREFIX COLOR_BRIGHT COLOR_SEPARATOR COLOR_FOREGROUND_RED COLOR_SUFFIX); return *color;}
32  const string& ErrorColor() {static string* color = new string(COLOR_PREFIX COLOR_BRIGHT COLOR_SEPARATOR COLOR_FOREGROUND_RED COLOR_SUFFIX); return *color;}
33  const string& WarnColor() {static string* color = new string(COLOR_PREFIX COLOR_BRIGHT COLOR_SEPARATOR COLOR_FOREGROUND_YELLOW COLOR_SUFFIX); return *color;}
34  const string& InfoColor() {static string* color = new string(COLOR_PREFIX COLOR_BRIGHT COLOR_SEPARATOR COLOR_FOREGROUND_GREEN COLOR_SUFFIX); return *color;}
35  const string& ProgColor() {static string* color = new string(COLOR_PREFIX COLOR_BRIGHT COLOR_SEPARATOR COLOR_FOREGROUND_BLUE COLOR_SUFFIX); return *color;}
36  const string& DebugColor() {static string* color = new string(COLOR_PREFIX COLOR_BRIGHT COLOR_SEPARATOR COLOR_FOREGROUND_CYAN COLOR_SUFFIX); return *color;}
37  const string& TraceColor() {static string* color = new string(COLOR_PREFIX COLOR_BRIGHT COLOR_SEPARATOR COLOR_FOREGROUND_WHITE COLOR_SUFFIX); return *color;}
38  const string& OtherColor() {static string* color = new string(COLOR_PREFIX COLOR_BRIGHT COLOR_SEPARATOR COLOR_FOREGROUND_WHITE COLOR_SUFFIX); return *color;}
39 
41  {
42  static unsigned& count()
43  {
44  static unsigned sCount = 0;
45  return sCount;
46  }
47 
48  static std::mutex& mutex()
49  {
50  static std::mutex sMutex;
51  return sMutex;
52  }
53 
54  typedef std::set< logger* > LoggerSet;
55  static std::shared_ptr<LoggerSet>& AllLoggers()
56  {
57  // construct-on-first-use strategy to avoid static initialization fiasco
58  static std::shared_ptr<LoggerSet> sAllLoggers = std::make_shared< LoggerSet >();
59  return sAllLoggers;
60  }
61 
62  static char* dateTimeFormat()
63  {
64  static char sDateTimeFormat[16];
65 
66  return sDateTimeFormat;
67  }
68 
69  static char* getTimeAbsoluteStr( bool aGetNewTime = false )
70  {
71  static char sTimeBuff[512];
72  static time_t sRawTime;
73  static tm* sProcessedTime;
74 
75  if( ! aGetNewTime ) return sTimeBuff;
76 
77  time(&sRawTime);
78 
79  sProcessedTime = localtime(&sRawTime);
80  strftime(sTimeBuff, 512, logger::Private::dateTimeFormat(), sProcessedTime);
81 
82  return sTimeBuff;
83  }
84 
85 
86  const char* fLogger;
87 
88  static bool& colored()
89  {
90 #ifndef _WIN32
91  static bool sColored = true;
92 #else
93  static bool sColored = false;
94 #endif
95  return sColored;
96  }
97 
98  static std::ostream*& out()
99  {
100  static std::ostream* sOut = &std::cout;
101  return sOut;
102  }
103 
104  static std::ostream*& err()
105  {
106  static std::ostream* sErr = &std::cerr;
107  return sErr;
108  }
109 
112 
114  {
115  // construct-on-first-use strategy to avoid static initialization fiasco
116  static ELevel sGlobalThreshold = logger::Private::filterMinimumLevel(ELevel::eDebug);
117  return sGlobalThreshold;
118  }
119 
120  static const char* level2Str(ELevel level)
121  {
122  switch(level)
123  {
124  case ELevel::eTrace : return "TRACE"; break;
125  case ELevel::eDebug : return "DEBUG"; break;
126  case ELevel::eInfo : return "INFO"; break;
127  case ELevel::eProg : return "PROG"; break;
128  case ELevel::eWarn : return "WARN"; break;
129  case ELevel::eError : return "ERROR"; break;
130  case ELevel::eFatal : return "FATAL"; break;
131  default : return "XXX";
132  }
133  }
134 
135  static string level2Color(ELevel level)
136  {
137  switch(level)
138  {
139  case ELevel::eTrace : return TraceColor(); break;
140  case ELevel::eDebug : return DebugColor(); break;
141  case ELevel::eInfo : return InfoColor(); break;
142  case ELevel::eProg : return ProgColor(); break;
143  case ELevel::eWarn : return WarnColor(); break;
144  case ELevel::eError : return ErrorColor(); break;
145  case ELevel::eFatal : return FatalColor(); break;
146  default : return OtherColor();
147  }
148  }
149 
151  {
152 #if defined(NDEBUG) && defined(STANDARD)
153  return level >= ELevel::eInfo ? level : ELevel::eInfo;
154 #elif defined(NDEBUG)
155  return level >= ELevel::eProg ? level : ELevel::eProg;
156 #else
157  return level;
158 #endif
159  }
160 
161 
162  void logCout(ELevel level, const string& message, const Location& loc)
163  {
164  logger::Private::mutex().lock();
165  logger::Private::getTimeAbsoluteStr( true );
166  if (logger::Private::colored())
167  {
168  //cout << color << KTLogger::Private::sTimeBuff << " [" << setw(5) << level << "] " << setw(16) << left << loc.fFileName << "(" << loc.fLineNumber << "): " << message << skKTEndColor << endl;
169  *logger::Private::out() << Private::level2Color(level) << logger::Private::getTimeAbsoluteStr() << " [" << setw(5) << Private::level2Str(level) << "] ";
170 #ifndef NDEBUG
171  *logger::Private::out() << "(tid " << std::this_thread::get_id() << ") ";
172 #endif
173  copy(loc.fFileName.end() - std::min< int >(loc.fFileName.size(), 16), loc.fFileName.end(), ostream_iterator<char>(*logger::Private::out()));
174  *logger::Private::out() << "(" << loc.fLineNumber << "): ";
175  *logger::Private::out() << message << EndColor() << endl;
176  }
177  else
178  {
179  //cout << KTLogger::Private::sTimeBuff << " [" << setw(5) << level << "] " << setw(16) << left << loc.fFileName << "(" << loc.fLineNumber << "): " << message << endl;
180  *logger::Private::out() << logger::Private::getTimeAbsoluteStr() << " [" << setw(5) << Private::level2Str(level) << "] ";
181 #ifndef NDEBUG
182  *logger::Private::out() << "(tid " << std::this_thread::get_id() << ") ";
183 #endif
184  copy(loc.fFileName.end() - std::min< int >(loc.fFileName.size(), 16), loc.fFileName.end(), ostream_iterator<char>(*logger::Private::out()));
185  *logger::Private::out() << "(" << loc.fLineNumber << "): ";
186  *logger::Private::out() << message << endl;
187  }
188  logger::Private::mutex().unlock();
189  }
190 
191  void logCerr(ELevel level, const string& message, const Location& loc)
192  {
193  logger::Private::mutex().lock();
194  logger::Private::getTimeAbsoluteStr();
195  if (logger::Private::colored())
196  {
197  //cout << color << KTLogger::Private::sTimeBuff << " [" << setw(5) << level << "] " << setw(16) << left << loc.fFileName << "(" << loc.fLineNumber << "): " << message << skKTEndColor << endl;
198  *logger::Private::err() << Private::level2Color(level) << logger::Private::getTimeAbsoluteStr() << " [" << setw(5) << Private::level2Str(level) << "] ";
199 #ifndef NDEBUG
200  *logger::Private::err() << "(tid " << std::this_thread::get_id() << ") ";
201 #endif
202  copy(loc.fFileName.end() - std::min< int >(loc.fFileName.size(), 16), loc.fFileName.end(), ostream_iterator<char>(*logger::Private::err()));
203  *logger::Private::err() << "(" << loc.fLineNumber << "): ";
204  *logger::Private::err() << message << EndColor() << endl;
205  }
206  else
207  {
208  //cout << KTLogger::Private::sTimeBuff << " [" << setw(5) << level << "] " << setw(16) << left << loc.fFileName << "(" << loc.fLineNumber << "): " << message << endl;
209  *logger::Private::err() << logger::Private::getTimeAbsoluteStr() << " [" << setw(5) << Private::level2Str(level) << "] ";
210 #ifndef NDEBUG
211  *logger::Private::err() << "(tid " << std::this_thread::get_id() << ") ";
212 #endif
213  copy(loc.fFileName.end() - std::min< int >(loc.fFileName.size(), 16), loc.fFileName.end(), ostream_iterator<char>(*logger::Private::err()));
214  *logger::Private::err() << "(" << loc.fLineNumber << "): ";
215  *logger::Private::err() << message << endl;
216  }
217  logger::Private::mutex().unlock();
218  }
219  };
220 
221 
222  logger::logger(const char* name) : fPrivate(new Private())
223  {
224  if( logger::Private::count() == 0 )
225  {
226  sprintf( logger::Private::dateTimeFormat(), "%%Y-%%m-%%d %%T" );
227  }
228 
230 
231  if (name == 0)
232  {
233  fPrivate->fLogger = "root";
234  }
235  else
236  {
237  const char* logName = strrchr(name, '/') ? strrchr(name, '/') + 1 : name;
238  fPrivate->fLogger = logName;
239  }
240 
241  UseGlobalLevel();
242  logger::Private::AllLoggers()->insert(this);
243 
244  //std::cerr << "created logger (" << fPrivate->count() << ") " << fPrivate->fLogger << std::endl;
245  }
246 
247  logger::logger(const std::string& name) : fPrivate(new Private())
248  {
249  if( logger::Private::count() == 0 )
250  {
251  sprintf( logger::Private::dateTimeFormat(), "%%Y-%%m-%%d %%T" );
252  }
253 
255 
256  fPrivate->fLogger = name.c_str();
257 
258  UseGlobalLevel();
259 
260  logger::Private::AllLoggers()->insert(this);
261 
262  //std::cerr << "created logger (" << fPrivate->count() << ") " << fPrivate->fLogger << std::endl;
263  }
264 
266  {
267  fPrivate->count()--;
268 
269  //std::cerr << "destructing logger (" << fPrivate->count() << ") " << fPrivate->fLogger << std::endl;
270  logger::Private::AllLoggers()->erase(this);
271  //std::cerr << "logger removed from set: " << fPrivate->fLogger << std::endl;
272  }
273 
274  bool logger::IsLevelEnabled(ELevel level) const
275  {
276  return level >= fPrivate->fThreshold;
277  }
278 
280  {
281  return fPrivate->fThreshold;
282  }
283 
284  void logger::SetLevel(ELevel level) const
285  {
286  fPrivate->fThreshold = logger::Private::filterMinimumLevel(level);
287  fPrivate->fThresholdIsGlobal = false;
288  }
289 
291  {
293  fPrivate->fThresholdIsGlobal = true;
294  }
295 
296  // static function
298  {
300  }
301 
302  // static function
304  {
306  for( logger::Private::LoggerSet::iterator logIt = logger::Private::AllLoggers()->begin(); logIt != logger::Private::AllLoggers()->end(); ++logIt)
307  {
308  if( (*logIt)->fPrivate->fThresholdIsGlobal )
309  {
310  (*logIt)->fPrivate->fThreshold = logger::Private::GlobalThreshold();
311  }
312  }
313  return;
314  }
315 
316  void logger::SetColored(bool flag)
317  {
318 #ifndef _WIN32
319  logger::Private::colored() = flag;
320 #else
321  std::cerr << "Colored logging is not enabled in Windows" << std::endl;
322 #endif
323  return;
324  }
325 
326  void logger::SetOutStream(std::ostream* stream)
327  {
328  logger::Private::out() = stream;
329  return;
330  }
331 
332  void logger::SetErrStream(std::ostream* stream)
333  {
334  logger::Private::err() = stream;
335  return;
336  }
337 
338  void logger::Log(ELevel level, const string& message, const Location& loc)
339  {
340  if (level >= ELevel::eWarn)
341  {
342  fPrivate->logCerr(level, message, loc);
343  }
344  else
345  {
346  fPrivate->logCout(level, message, loc);
347  }
348  }
349 }
std::string fFileName
Definition: logger.hh:143
#define COLOR_BRIGHT
Definition: logger.hh:47
ELevel GetLevel() const
Definition: logger.cc:279
const string & TraceColor()
Definition: logger.cc:37
const char * fLogger
Definition: logger.cc:86
const string & OtherColor()
Definition: logger.cc:38
const string & EndColor()
Definition: logger.cc:30
virtual ~logger()
Definition: logger.cc:265
void logCerr(ELevel level, const string &message, const Location &loc)
Definition: logger.cc:191
const string & FatalColor()
Definition: logger.cc:31
static std::mutex & mutex()
Definition: logger.cc:48
#define COLOR_NORMAL
Definition: logger.hh:46
#define COLOR_SEPARATOR
Definition: logger.hh:56
static ELevel & GlobalThreshold()
Definition: logger.cc:113
STL namespace.
static char * dateTimeFormat()
Definition: logger.cc:62
static bool & colored()
Definition: logger.cc:88
void Log(ELevel level, const std::string &message, const Location &loc=Location())
Definition: logger.cc:338
#define COLOR_FOREGROUND_WHITE
Definition: logger.hh:53
static void SetColored(bool flag)
Definition: logger.cc:316
void UseGlobalLevel() const
Definition: logger.cc:290
Contains the logger class and macros, based on Kasper&#39;s KLogger class.
static std::ostream *& out()
Definition: logger.cc:98
static const char * level2Str(ELevel level)
Definition: logger.cc:120
static string level2Color(ELevel level)
Definition: logger.cc:135
const string & ProgColor()
Definition: logger.cc:35
static void SetErrStream(std::ostream *stream)
Definition: logger.cc:332
static unsigned & count()
Definition: logger.cc:42
logger(const char *name=0)
Definition: logger.cc:222
const string & ErrorColor()
Definition: logger.cc:32
static ELevel filterMinimumLevel(ELevel level)
Definition: logger.cc:150
bool IsLevelEnabled(ELevel level) const
Definition: logger.cc:274
const string & DebugColor()
Definition: logger.cc:36
const string & InfoColor()
Definition: logger.cc:34
#define COLOR_SUFFIX
Definition: logger.hh:55
void SetLevel(ELevel level) const
Definition: logger.cc:284
const string & WarnColor()
Definition: logger.cc:33
#define COLOR_FOREGROUND_GREEN
Definition: logger.hh:49
static logger::ELevel GetGlobalLevel()
Definition: logger.cc:297
static void SetOutStream(std::ostream *stream)
Definition: logger.cc:326
std::set< logger *> LoggerSet
Definition: logger.cc:54
#define COLOR_FOREGROUND_BLUE
Definition: logger.hh:51
#define COLOR_FOREGROUND_CYAN
Definition: logger.hh:52
#define COLOR_PREFIX
Definition: logger.hh:54
static std::ostream *& err()
Definition: logger.cc:104
#define COLOR_FOREGROUND_RED
Definition: logger.hh:48
static char * getTimeAbsoluteStr(bool aGetNewTime=false)
Definition: logger.cc:69
std::shared_ptr< Private > fPrivate
Definition: logger.hh:298
static void SetGlobalLevel(ELevel level)
Definition: logger.cc:303
#define COLOR_FOREGROUND_YELLOW
Definition: logger.hh:50
void logCout(ELevel level, const string &message, const Location &loc)
Definition: logger.cc:162
static std::shared_ptr< LoggerSet > & AllLoggers()
Definition: logger.cc:55