bugfix
[u/mrichter/AliRoot.git] / STEER / AliLog.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 ///////////////////////////////////////////////////////////////////////////////
19 //                                                                           //
20 // class for logging debug, info and error messages                          //
21 //                                                                           //
22 // The AliLog class is a singleton class. It allows to steer the output      //
23 // level and output streams for different types of messages via static       //
24 // methods.                                                                  //
25 //                                                                           //
26 // It also handles the messages produces by the preprocessor macros defined  //
27 // in the header file: AliDebug, AliInfo, AliWarning, AliError, AliFatal.    //
28 //                                                                           //
29 // More details about the message logging can be found on the ALICE Offline  //
30 // web page.                                                                 //
31 //                                                                           //
32 ///////////////////////////////////////////////////////////////////////////////
33
34 #include <TError.h>
35 #include <TNamed.h>
36 #include <TSystem.h>
37
38 #include "AliLog.h"
39
40 ClassImp(AliLog)
41
42
43 AliLog* AliLog::fgInstance = NULL;
44
45 Bool_t AliLog::fgDebugEnabled = kTRUE;
46
47
48 //_____________________________________________________________________________
49 AliLog::AliLog() :
50   TObject(),
51   fGlobalLogLevel(kInfo),
52   fModuleDebugLevels(),
53   fClassDebugLevels()
54 {
55 // default constructor: set default values
56
57   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
58     fOutputTypes[iType] = 0;
59     fFileNames[iType] = "";
60     fOutputFiles[iType] = NULL;
61
62     fPrintType[iType] = kTRUE;
63     fPrintModule[iType] = kFALSE;
64     fPrintScope[iType] = kTRUE;
65     fPrintLocation[iType] = (iType == kDebug);  
66   }
67
68   SetHandleRootMessages(kTRUE);
69
70   // replace the previous instance by this one
71   if (fgInstance) delete fgInstance;
72   fgInstance = this;
73 }
74
75 //_____________________________________________________________________________
76 AliLog::~AliLog()
77 {
78 // destructor: clean up and reset instance pointer
79
80   for (Int_t i = 0; i < fModuleDebugLevels.GetEntriesFast(); i++) {
81     if (fModuleDebugLevels[i]) fModuleDebugLevels[i]->Delete();
82   }
83   fClassDebugLevels.Delete();
84   for (Int_t i = 0; i < fClassDebugLevels.GetEntriesFast(); i++) {
85     if (fClassDebugLevels[i]) fClassDebugLevels[i]->Delete();
86   }
87   fClassDebugLevels.Delete();
88
89   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
90     CloseFile(iType);
91   }
92   fflush(stderr);
93   fflush(stdout);
94
95   fgInstance = NULL;
96 }
97
98 //_____________________________________________________________________________
99 AliLog::AliLog(const AliLog& log) :
100   TObject(log)
101 {
102 // copy constructor
103
104   Fatal("AliLog", "copy constructor not implemented");
105 }
106
107 //_____________________________________________________________________________
108 AliLog& AliLog::operator = (const AliLog& /*log*/)
109 {
110 // assignment operator
111
112   Fatal("operator =", "assignment operator not implemented");
113   return *this;
114 }
115
116
117 //_____________________________________________________________________________
118 void AliLog::RootErrorHandler(Int_t level, Bool_t abort, 
119                               const char* location, const char* message)
120 {
121 // new error handler for messages from root
122
123   switch (level) {
124   case ::kFatal    : level = kFatal; break;
125   case ::kSysError :
126     DefaultErrorHandler(level, abort, location, message);
127     return;
128   case ::kBreak    :
129     DefaultErrorHandler(level, abort, location, message);
130     return;
131   case ::kError    : level = kError; break;
132   case ::kWarning  : level = kWarning; break;
133   case ::kInfo     : level = kInfo; break;
134   default          : level = kDebug; break;
135   }
136   AliLog::Message(level, message, "ROOT", NULL, location, NULL, 0);
137 }
138
139
140 //_____________________________________________________________________________
141 void AliLog::EnableDebug(Bool_t enabled)
142 {
143 // enable or disable debug output
144
145   fgDebugEnabled = enabled;
146 }
147
148 //_____________________________________________________________________________
149 void AliLog::SetGlobalLogLevel(EType type)
150 {
151 // set the global debug level
152
153   if (!fgInstance) new AliLog; 
154   fgInstance->fGlobalLogLevel = type;
155 }
156
157 //_____________________________________________________________________________
158 Int_t AliLog::GetGlobalLogLevel()
159 {
160 // get the global debug level
161
162   if (!fgInstance) new AliLog;
163   return fgInstance->fGlobalLogLevel;
164 }
165
166 //_____________________________________________________________________________
167 void AliLog::SetGlobalDebugLevel(Int_t level)
168 {
169 // set the global debug level
170
171   if (!fgInstance) new AliLog;
172   if (level < -kDebugOffset) level = -kDebugOffset;
173   fgInstance->fGlobalLogLevel = kDebugOffset + level;
174 }
175
176 //_____________________________________________________________________________
177 Int_t AliLog::GetGlobalDebugLevel()
178 {
179 // get the global debug level
180
181   if (!fgInstance) new AliLog;
182   return fgInstance->fGlobalLogLevel - kDebugOffset;
183 }
184
185 //_____________________________________________________________________________
186 void AliLog::SetModuleDebugLevel(const char* module, Int_t level)
187 {
188 // set the debug level for the given module
189
190   if (!module) return;
191   if (!fgInstance) new AliLog;
192   TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module);
193   if (!obj) {
194     obj = new TNamed(module, module);
195     fgInstance->fModuleDebugLevels.Add(obj);
196   }
197   level += kDebugOffset;
198   if (level < kFatal) level = kFatal;
199   obj->SetUniqueID(level);
200 }
201
202 //_____________________________________________________________________________
203 void AliLog::ClearModuleDebugLevel(const char* module)
204 {
205 // remove the setting of the debug level for the given module
206
207   if (!module) return;
208   if (!fgInstance) new AliLog;
209   TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module);
210   if (obj) delete fgInstance->fModuleDebugLevels.Remove(obj);
211 }
212
213 //_____________________________________________________________________________
214 void AliLog::SetClassDebugLevel(const char* className, Int_t level)
215 {
216 // set the debug level for the given class
217
218   if (!className) return;
219   if (!fgInstance) new AliLog;
220   TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
221   if (!obj) {
222     obj = new TNamed(className, className);
223     fgInstance->fClassDebugLevels.Add(obj);
224   }
225   level += kDebugOffset;
226   if (level < kFatal) level = kFatal;
227   obj->SetUniqueID(level);
228 }
229
230 //_____________________________________________________________________________
231 void AliLog::ClearClassDebugLevel(const char* className)
232 {
233 // remove the setting of the debug level for the given class
234
235   if (!className) return;
236   if (!fgInstance) new AliLog;
237   TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
238   if (obj) delete fgInstance->fClassDebugLevels.Remove(obj);
239 }
240
241
242 //_____________________________________________________________________________
243 void AliLog::SetStandardOutput()
244 {
245 // write all log messages to the standard output (stdout)
246
247   if (!fgInstance) new AliLog;
248   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
249     fgInstance->CloseFile(iType);
250     fgInstance->fOutputTypes[iType] = 0;
251   }
252 }
253
254 //_____________________________________________________________________________
255 void AliLog::SetStandardOutput(EType type)
256 {
257 // write log messages of the given type to the standard output (stdout)
258
259   if ((type < kFatal) || (type >= kMaxType)) return;
260   if (!fgInstance) new AliLog;
261   fgInstance->CloseFile(type);
262   fgInstance->fOutputTypes[type] = 0;
263 }
264
265 //_____________________________________________________________________________
266 void AliLog::SetErrorOutput()
267 {
268 // write all log messages to the error output (stderr)
269
270   if (!fgInstance) new AliLog;
271   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
272     fgInstance->CloseFile(iType);
273     fgInstance->fOutputTypes[iType] = 1;
274   }
275 }
276
277 //_____________________________________________________________________________
278 void AliLog::SetErrorOutput(EType type)
279 {
280 // write log messages of the given type to the error output (stderr)
281
282   if ((type < kFatal) || (type >= kMaxType)) return;
283   if (!fgInstance) new AliLog;
284   fgInstance->CloseFile(type);
285   fgInstance->fOutputTypes[type] = 1;
286 }
287
288 //_____________________________________________________________________________
289 void AliLog::SetFileOutput(const char* fileName)
290 {
291 // write all log messages to the given file
292
293   if (!fgInstance) new AliLog;
294   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
295     if ((fgInstance->fOutputTypes[iType] == 2) && 
296         (fgInstance->fFileNames[iType].CompareTo(fileName) != 0)) {
297       fgInstance->CloseFile(iType);
298     }
299     fgInstance->fOutputTypes[iType] = 2;
300     fgInstance->fFileNames[iType] = fileName;
301     fgInstance->fOutputFiles[iType] = NULL;
302   }
303 }
304
305 //_____________________________________________________________________________
306 void AliLog::SetFileOutput(EType type, const char* fileName)
307 {
308 // write log messages of the given type to the given file
309
310   if ((type < kFatal) || (type >= kMaxType)) return;
311   if (!fgInstance) new AliLog;
312   if ((fgInstance->fOutputTypes[type] == 2) && 
313       (fgInstance->fFileNames[type].CompareTo(fileName) != 0)) {
314     fgInstance->CloseFile(type);
315   }
316   fgInstance->fOutputTypes[type] = 2;
317   fgInstance->fFileNames[type] = fileName;
318   fgInstance->fOutputFiles[type] = NULL;
319 }
320
321 //_____________________________________________________________________________
322 void AliLog::CloseFile(Int_t type)
323 {
324 // close the file for the given type if needed
325
326   if ((fOutputTypes[type] == 2) && fOutputFiles[type]) {
327     Bool_t closeFile = kTRUE;
328     for (Int_t iType = kFatal; iType < kMaxType; iType++) {
329       if ((iType != type) && (fOutputFiles[iType] == fOutputFiles[type])) {
330         closeFile = kFALSE;
331       }
332     }
333     if (closeFile) fclose(fOutputFiles[type]);
334   }
335   fOutputFiles[type] = NULL;
336   fFileNames[type] = "";
337   fOutputTypes[type] = 0;
338 }
339
340 //_____________________________________________________________________________
341 FILE* AliLog::GetOutputStream(Int_t type)
342 {
343 // get the output stream for the given type of messages
344
345   if (fOutputTypes[type] == 0) return stdout;
346   else if (fOutputTypes[type] == 1) return stderr;
347   else if (fOutputTypes[type] == 2) {
348     if (!fOutputFiles[type]) {
349       FILE* file = NULL;
350       if (!fFileNames[type].IsNull()) {
351         for (Int_t iType = kFatal; iType < kMaxType; iType++) {
352           if ((iType != type) && 
353               (fFileNames[iType].CompareTo(fFileNames[type]) == 0) &&
354               fOutputFiles[iType]) {
355             file = fOutputFiles[iType];
356             break;
357           }
358         }
359         if (!file) file = fopen(fFileNames[type], "a");
360       }
361       fOutputFiles[type] = file;
362       if (!file) CloseFile(type);
363     }
364     if (fOutputFiles[type]) return fOutputFiles[type];
365   }
366
367   return stdout;
368 }
369
370 //_____________________________________________________________________________
371 void AliLog::Flush()
372 {
373 // flush the output streams
374
375   if (!fgInstance) new AliLog;
376   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
377     if (fgInstance->fOutputFiles[iType]) {
378       fflush(fgInstance->fOutputFiles[iType]);
379     }
380   }
381   fflush(stderr);
382   fflush(stdout);
383 }
384
385
386 //_____________________________________________________________________________
387 void AliLog::SetHandleRootMessages(Bool_t on)
388 {
389 // enable or disable the handling of messages form root
390
391   if (on) {
392     SetErrorHandler(RootErrorHandler);
393   } else {
394     SetErrorHandler(DefaultErrorHandler);
395   }
396 }
397
398
399 //_____________________________________________________________________________
400 void AliLog::SetPrintType(Bool_t on)
401 {
402 // switch on or off the printing of the message type for all message types
403
404   if (!fgInstance) new AliLog;
405   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
406     fgInstance->fPrintType[iType] = on;
407   }
408 }
409
410 //_____________________________________________________________________________
411 void AliLog::SetPrintType(EType type, Bool_t on)
412 {
413 // switch on or off the printing of the message type for the given message type
414
415   if ((type < kFatal) || (type >= kMaxType)) return;
416   if (!fgInstance) new AliLog;
417   fgInstance->fPrintType[type] = on;
418 }
419
420 //_____________________________________________________________________________
421 void AliLog::SetPrintModule(Bool_t on)
422 {
423 // switch on or off the printing of the module for all message types
424
425   if (!fgInstance) new AliLog;
426   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
427     fgInstance->fPrintModule[iType] = on;
428   }
429 }
430
431 //_____________________________________________________________________________
432 void AliLog::SetPrintModule(EType type, Bool_t on)
433 {
434 // switch on or off the printing of the module for the given message type
435
436   if ((type < kFatal) || (type >= kMaxType)) return;
437   if (!fgInstance) new AliLog;
438   fgInstance->fPrintModule[type] = on;
439 }
440
441 //_____________________________________________________________________________
442 void AliLog::SetPrintScope(Bool_t on)
443 {
444 // switch on or off the printing of the scope/class name for all message types
445
446   if (!fgInstance) new AliLog;
447   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
448     fgInstance->fPrintScope[iType] = on;
449   }
450 }
451
452 //_____________________________________________________________________________
453 void AliLog::SetPrintScope(EType type, Bool_t on)
454 {
455 // switch on or off the printing of the scope/class name
456 // for the given message type
457
458   if ((type < kFatal) || (type >= kMaxType)) return;
459   if (!fgInstance) new AliLog;
460   fgInstance->fPrintScope[type] = on;
461 }
462
463 //_____________________________________________________________________________
464 void AliLog::SetPrintLocation(Bool_t on)
465 {
466 // switch on or off the printing of the file name and line number
467 // for all message types
468
469   if (!fgInstance) new AliLog;
470   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
471     fgInstance->fPrintLocation[iType] = on;
472   }
473 }
474
475 //_____________________________________________________________________________
476 void AliLog::SetPrintLocation(EType type, Bool_t on)
477 {
478 // switch on or off the printing of the file name and line number 
479 // for the given message type
480
481   if ((type < kFatal) || (type >= kMaxType)) return;
482   if (!fgInstance) new AliLog;
483   fgInstance->fPrintLocation[type] = on;
484 }
485
486
487 //_____________________________________________________________________________
488 void AliLog::Write(const char* name, Int_t option)
489 {
490 // write the log object with the given name and option to the current file
491
492   if (!fgInstance) new AliLog;
493   fgInstance->TObject::Write(name, option);
494 }
495
496
497 //_____________________________________________________________________________
498 UInt_t AliLog::GetLogLevel(const char* module, const char* className) const
499 {
500 // get the logging level for the given module and class
501
502   if (!fgInstance) new AliLog;
503   TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
504   if (obj) return obj->GetUniqueID();
505   obj = fgInstance->fModuleDebugLevels.FindObject(module);
506   if (obj) return obj->GetUniqueID();
507   return fgInstance->fGlobalLogLevel;
508 }
509
510 //_____________________________________________________________________________
511 Int_t AliLog::GetDebugLevel(const char* module, const char* className)
512 {
513 // get the debug level for the given module and class
514
515   if (!fgInstance) new AliLog;
516   return fgInstance->GetLogLevel(module, className) - kDebugOffset;
517 }
518
519 //_____________________________________________________________________________
520 void AliLog::Message(UInt_t level, const char* message, 
521                      const char* module, const char* className,
522                      const char* function, const char* file, Int_t line)
523 {
524 // print a log message
525
526   if (!fgInstance) new AliLog;
527
528   // get the message type
529   static const char* typeNames[kMaxType] = 
530     {"Fatal", "Error", "Warning", "Info", "Debug"};
531   UInt_t type = level;
532   if (type >= kMaxType) type = kMaxType - 1;
533
534   // print the message if the debug level allows
535   if (level <= fgInstance->GetLogLevel(module, className)) {
536     if (fgInstance->fPrintType[type]) {
537       fprintf(fgInstance->GetOutputStream(type), "%s in ", typeNames[type]);
538     }
539     fprintf(fgInstance->GetOutputStream(type), "<");
540     if (fgInstance->fPrintModule[type] && module) {
541       fprintf(fgInstance->GetOutputStream(type), "%s/", module);
542     }
543     if (fgInstance->fPrintScope[type] && className) {
544       fprintf(fgInstance->GetOutputStream(type), "%s::", className);
545     }
546     fprintf(fgInstance->GetOutputStream(type), "%s>: %s", function, message);
547     if (fgInstance->fPrintLocation[type] && file) {
548       fprintf(fgInstance->GetOutputStream(type), " (%s:%.0d)", file, line);
549     }
550     fprintf(fgInstance->GetOutputStream(type), "\n");
551   }
552
553   // abort in case of a fatal message
554   if (type == kFatal) {
555     delete fgInstance;
556     if (gSystem) {
557       gSystem->StackTrace();
558       gSystem->Abort();
559     } else {
560       ::abort();
561     }
562   }
563 }
564
565 //_____________________________________________________________________________
566 void AliLog::Debug(UInt_t level, const char* message, 
567                    const char* module, const char* className,
568                    const char* function, const char* file, Int_t line)
569 {
570 // print a debug message
571
572   if (level == 0) level = 1;
573   level += kDebugOffset;
574   Message(level, message, module, className, function, file, line);
575 }