EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FairLogger.cxx
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file FairLogger.cxx
1 /*
2  * FairLogger.cxx
3  *
4  * Created on: Mar 03, 2011
5  * Author: f.uhlig
6  */
7 
8 //#include <ostream>
9 
10 #include "FairLogger.h"
11 
12 #include "TString.h" // TString
13 #include "TSystem.h" // gSystem
14 
15 #include <iostream> // std::cerr
16 #include <iomanip> // std::setw
17 #include <cstdlib> // abort
18 
20 
22 
24  :
25  fLogFileName(""),
26  fLogToScreen(kTRUE),
27  fLogToFile(kFALSE),
28  fLogColored(kFALSE),
29  fLogFileLevel(INFO),
30  fLogScreenLevel(INFO),
31  fLogVerbosityLevel(verbosityLOW),
32  fBufferSize(1024),
33  fBufferSizeNeeded(-1),
34  fDynamicBuffer(fBufferSize),
35  fBufferPointer(&fDynamicBuffer[0]),
36  fMinLogLevel(INFO),
37  fLevel(INFO),
38  fScreenStream(&std::cout),
39  fFileStream(NULL),
40  fNullStream(new std::ostream(0)),
41  fLogFileOpen(kFALSE),
42  fIsNewLine(kTRUE)
43 {
44 }
45 
47 {
48  CloseLogFile();
49 }
50 
52 {
53  if (!instance) {
54  instance = new FairLogger();
55  }
56  return instance;
57 }
58 
59 void FairLogger::Fatal(const char* file, const char* line, const char* func,
60  const char* format, ...)
61 {
62  va_list ap;
63  va_start(ap, format);
64  Log(FATAL, file, line, func, format, ap);
65  va_end(ap);
66 }
67 
68 void FairLogger::Error(const char* file, const char* line, const char* func,
69  const char* format, ...)
70 {
71  if (IsLogNeeded(ERROR)) {
72  va_list ap;
73  va_start(ap, format);
74  Log(ERROR, file, line, func, format, ap);
75  va_end(ap);
76  }
77 }
78 
79 void FairLogger::Warning(const char* file, const char* line, const char* func,
80  const char* format, ...)
81 {
82  if (IsLogNeeded(WARNING)) {
83  va_list ap;
84  va_start(ap, format);
85  Log(WARNING, file, line, func, format, ap);
86  va_end(ap);
87  }
88 }
89 
90 void FairLogger::Info(const char* file, const char* line, const char* func,
91  const char* format, ...)
92 {
93  if (IsLogNeeded(INFO)) {
94  va_list ap;
95  va_start(ap, format);
96  Log(INFO, file, line, func, format, ap);
97  va_end(ap);
98  }
99 }
100 
101 void FairLogger::Debug(const char* file, const char* line, const char* func,
102  const char* format, ...)
103 {
104  if (IsLogNeeded(DEBUG)) {
105  va_list ap;
106  va_start(ap, format);
107  Log(DEBUG, file, line, func, format, ap);
108  va_end(ap);
109  }
110 }
111 
112 void FairLogger::Debug1(const char* file, const char* line, const char* func,
113  const char* format, ...)
114 {
115  if (IsLogNeeded(DEBUG1)) {
116  va_list ap;
117  va_start(ap, format);
118  Log(DEBUG1, file, line, func, format, ap);
119  va_end(ap);
120  }
121 }
122 
123 void FairLogger::Debug2(const char* file, const char* line, const char* func,
124  const char* format, ...)
125 {
126  if (IsLogNeeded(DEBUG2)) {
127  va_list ap;
128  va_start(ap, format);
129  Log(DEBUG2, file, line, func, format, ap);
130  va_end(ap);
131  }
132 }
133 
134 void FairLogger::Debug3(const char* file, const char* line, const char* func,
135  const char* format, ...)
136 {
137  if (IsLogNeeded(DEBUG3)) {
138  va_list ap;
139  va_start(ap, format);
140  Log(DEBUG3, file, line, func, format, ap);
141  va_end(ap);
142  }
143 }
144 
145 void FairLogger::Debug4(const char* file, const char* line, const char* func,
146  const char* format, ...)
147 {
148  if (IsLogNeeded(DEBUG4)) {
149  va_list ap;
150  va_start(ap, format);
151  Log(DEBUG4, file, line, func, format, ap);
152  va_end(ap);
153  }
154 }
155 
156 void FairLogger::Log(FairLogLevel level, const char* file, const char* line,
157  const char* func, const char* format, va_list arglist)
158 {
159  // If the format string together with the argument list was used once it can't
160  // be used another time. Don't know why but if we do so the arguments are not
161  // correct any longer and the program may crash (On Mac OSX). Even if it does
162  // not crash it does not work as expected.
163  // To vercome the problem the output is written to a buffer which then can be
164  // used several times.
165 
166  if(fLogToFile && !fLogFileOpen) {
167  OpenLogFile();
168  }
169 
170  fLevel = level;
171  while (1) {
172  fBufferSizeNeeded = vsnprintf(fBufferPointer, fBufferSize, format, arglist);
173 
174  // Try to vsnprintf into our buffer.
175  // int needed = vsnprintf (buf, size, fmt, ap);
176  // NB. C99 (which modern Linux and OS X follow) says vsnprintf
177  // failure returns the length it would have needed. But older
178  // glibc and current Windows return -1 for failure, i.e., not
179  // telling us how much was needed.
180 
181  if (fBufferSizeNeeded <= (int)fBufferSize && fBufferSizeNeeded >= 0) {
182  // It fit fine so we're done.
183  GetOutputStream(level, file, line, func) <<
184  std::string(fBufferPointer, (size_t) fBufferSizeNeeded)<<
185  " " << FairLogger::endl;
186 
187  break;
188  }
189 
190  // vsnprintf reported that it wanted to write more characters
191  // than we allotted. So try again using a dynamic buffer. This
192  // doesn't happen very often if we chose our initial size well.
194  ? (fBufferSizeNeeded+1) : (fBufferSize*2);
195 
196  fDynamicBuffer.resize (fBufferSize);
197  }
198 }
199 
201 {
202  if (fFileStream) {
203  CloseLogFile();
204  delete fFileStream;
205  fFileStream = NULL;
206  remove(fLogFileName);
207  }
208 
209  fLogFileName = name;
210  OpenLogFile();
211 
212 }
213 
215 {
216  dynamic_cast<std::ofstream*>(fFileStream)->close();
217 }
218 
220 {
221  // Check if the log file name is set. If not use a default logfile with
222  // the name FairLogfile_<pid>.log. <pid> is the pid of the runing job.
223  TString logfile = fLogFileName;
224  if (logfile.IsNull()) {
225  Int_t PID = gSystem->GetPid();
226  logfile = "FairLogfile_";
227  logfile += PID;
228  logfile += ".log";
229 
230  }
231 
232  // Check if filename contains a full path. If not create logfile
233  // in the current directory.
234  // TODO(F.U.): Check if the path exists and is writeable.
235  if (!logfile.Contains('/')) {
236  logfile = "./" + logfile;
237  }
238 
239  if (fFileStream) {
240  CloseLogFile();
241  delete fFileStream;
242  fFileStream = NULL;
243  }
244 
245  fFileStream = new std::ofstream(logfile.Data());
246 
247  fLogFileOpen = kTRUE;
248 }
249 
251 {
252  // Convert string to upper case
253  // Return the according log level
254  // in case the level is not known return info level
255  TString level = levelc;
256  level.ToUpper();
257  if (level == "FATAL") { return FATAL; }
258  if (level == "ERROR") { return ERROR; }
259  if (level == "WARNING") { return WARNING; }
260  if (level == "INFO") { return INFO; }
261  if (level == "DEBUG") { return DEBUG; }
262  if (level == "DEBUG1") { return DEBUG1; }
263  if (level == "DEBUG2") { return DEBUG2; }
264  if (level == "DEBUG3") { return DEBUG3; }
265  if (level == "DEBUG4") { return DEBUG4; }
266  FAIRLOG(ERROR)<<"Log level \""<<level<<"\" not supported. Use default level \"INFO\"."<<FairLogger::endl;
267  return INFO;
268 }
269 
271 {
272  // Convert string to upper case
273  // Return the according log verbosity level
274  // in case the level is not known return low verbosity level
275  TString vlevel = vlevelc;
276  vlevel.ToUpper();
277  if (vlevel == "HIGH") { return verbosityHIGH; }
278  if (vlevel == "MEDIUM") { return verbosityMEDIUM; }
279  if (vlevel == "LOW") { return verbosityLOW; }
280  FAIRLOG(ERROR)<<"Verbosity level \""<<vlevel<<"\" not supported. Use default level \"LOW\"."<<FairLogger::endl;
281  return verbosityLOW;
282 }
283 
285 {
286  time_t rawtime;
287  struct tm* timeinfo;
288 
289  time(&rawtime);
290  timeinfo = localtime(&rawtime);
291 
292  strftime(fTimeBuffer, 80, "[%d.%m.%Y %X] ", timeinfo);
293 }
295 {
297 }
298 
300 {
301  if (logLevel <= fMinLogLevel) {
302  return true;
303  } else {
304  return false;
305  }
306 }
307 
308 FairLogger& FairLogger::GetOutputStream(FairLogLevel level, const char* file, const char* line, const char* func)
309 {
310 
311  fLevel = level;
312 
313  if (level == FATAL) {
314  fLogToScreen = true;
316  fLogColored = true;
317  }
318 
319 
320  if (fIsNewLine) {
321  if ( (fLogToScreen && level <= fLogScreenLevel) ) {
322 
323  if ( fLogColored ) {
324  *fScreenStream << LogLevelColor[level];
325  }
326 
327  *fScreenStream << "[" << std::setw(7) << std::left << LogLevelString[level] <<"] ";
328 
330  GetTime();
332  }
333 
335  TString bla(file);
336  Ssiz_t pos = bla.Last('/');
337  TString s2(bla(pos+1, bla.Length()));
338  TString s3 = s2 + "::" + func + ":" + line;
339  *fScreenStream << "[" << s3 <<"] ";
340  }
341  }
342 
343  if ( fLogToFile && level <= fLogFileLevel ) {
344  if(!fLogFileOpen) {
345  OpenLogFile();
346  }
347 
348  *fFileStream << "[" << std::setw(7) << std::left << LogLevelString[level] <<"] ";
349 
351  GetTime();
353  }
354 
356  TString bla(file);
357  Ssiz_t pos = bla.Last('/');
358  TString s2(bla(pos+1, bla.Length()));
359  TString s3 = s2 + "::" + func + ":" + line;
360  *fFileStream << "[" << s3 <<"] ";
361  }
362  }
363  fIsNewLine = kFALSE;
364  }
365  return *this;
366 }
367 
368 
369 #if (__GNUC__ >= 3)
370 FairLogger& FairLogger::operator<<(std::ios_base& (*manip) (std::ios_base&))
371 {
373  *(fScreenStream) << manip;
374  }
375 
377  *(fFileStream) << manip;
378  }
379 
380  return *this;
381 }
382 #endif
383 
384 FairLogger& FairLogger::operator<<(std::ostream& (*manip) (std::ostream&))
385 {
387  *(fScreenStream) << manip;
388  }
389 
391  *(fFileStream) << manip;
392  }
393 
394  return *this;
395 }
396 
397 std::ostream& FairLogger::endl(std::ostream& strm)
398 {
399 
400  gLogger->fIsNewLine = kTRUE;
401  if ( (gLogger->fLogToScreen && gLogger->fLevel <= gLogger->fLogScreenLevel) ) {
402  if (gLogger->fLogColored) {
403  *(gLogger->fScreenStream) << "\33[00;30m" << std::endl;
404  } else {
405  *(gLogger->fScreenStream) << std::endl;
406  }
407  }
408 
409  if (gLogger->fLogToFile &&
410  gLogger->fLevel <= gLogger->fLogFileLevel) {
411  *(gLogger->fFileStream) << std::endl;
412  }
413 
414  if (gLogger->fLevel == FATAL) {
415  flush(strm);
416  gLogger->LogFatalMessage(strm);
417  }
418 
419  return strm;
420 }
421 
422 std::ostream& FairLogger::flush(std::ostream& strm)
423 {
424  if (gLogger->fLogToScreen) {
425  *(gLogger->fScreenStream) << std::flush;
426  }
427  if (gLogger->fLogToFile) {
428  *(gLogger->fFileStream) << std::flush;
429  }
430  return strm;
431 }
432 
433 void FairLogger::LogFatalMessage(std::ostream& strm)
434 {
435  // Since Fatal indicates a fatal error it is maybe usefull to have
436  // system information from the incident. Since the output on the screen
437  // does not help the noraml user, the stderr is redirected into a special
438  // core dump file for later usage.
439  // Fatal also indicates a problem which is so severe that the process should
440  // not go on, so the process is aborted.
441 
443 
444  *fScreenStream << "[" << std::setw(7) << std::left << LogLevelString[FATAL] <<"] ";
445 
446  GetTime();
448 
449  *fScreenStream << "We stop the execution of the process at this point.\n";
450 
451  if ( fLogToFile ) {
452  *fFileStream << "[" << std::setw(7) << std::left << LogLevelString[FATAL] <<"] ";
453 
455  *fFileStream << "We stop the execution of the process at this point.\n";
456  }
457 
458  if (gSystem) {
459  TString corefile = "core_dump_";
460  Int_t PID = gSystem->GetPid();
461  corefile += PID;
462 
463 
464  *fScreenStream << LogLevelColor[FATAL];
465 
466  *fScreenStream << "[" << std::setw(7) << std::left << LogLevelString[FATAL] <<"] ";
467 
468  GetTime();
470 
471  *fScreenStream << "For later analysis we write a core dump to " <<
472  corefile << " \n";
473 
474 
475  if ( fLogToFile ) {
476  *fFileStream << "[" << std::setw(7) << std::left << LogLevelString[FATAL] <<"] ";
477 
479  *fFileStream << "For later analysis we write a core dump to" <<
480  corefile << "\n";
481  }
482 
483  *(gLogger->fScreenStream) << "\33[00;30m" << std::endl;
484 
485  flush(strm);
486  freopen(corefile, "w", stderr);
487  gSystem->StackTrace();
488  fclose(stderr);
489  gSystem->Abort(1);
490  } else {
491  abort();
492  }
493 
494 }
495 
496 // Needed for the time beeing, since the tests can't work with
497 // output which goes to cout.
498 // TODO: Change testst to be able to handle output which goes
499 // to cerr.
500 void FairLogger::SetScreenStreamToCerr(bool errorStream)
501 {
502  if(errorStream) {
503  fScreenStream = &std::cerr;
504  } else {
505  fScreenStream = &std::cout;
506  }
507 }
508 
509