59d54800b223856f4d76f0326c48e5ea7fd0e38e
[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 <strings.h>
35 #include <Riostream.h>
36 #include <TError.h>
37 #include <TNamed.h>
38 #include <TSystem.h>
39 #include <TEnv.h>
40
41 #include "AliLog.h"
42
43 ClassImp(AliLog)
44
45
46 AliLog* AliLog::fgInstance = NULL;
47
48 Bool_t AliLog::fgDebugEnabled = kTRUE;
49
50
51 //_____________________________________________________________________________
52 AliLog::AliLog() :
53   TObject(),
54   fGlobalLogLevel(kInfo),
55   fModuleDebugLevels(),
56   fClassDebugLevels(),
57   fPrintRepetitions(kTRUE),
58   fRepetitions(0),
59   fLastType(0),
60   fLastMessage(),
61   fLastModule(),
62   fLastClassName(),
63   fLastFunction(),
64   fLastFile(),
65   fLastLine(0)
66 {
67 // default constructor: set default values
68
69   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
70     fOutputTypes[iType] = 0;
71     fFileNames[iType] = "";
72     fOutputFiles[iType] = NULL;
73     fOutputStreams[iType] = NULL;
74
75     fPrintType[iType] = kTRUE;
76     fPrintModule[iType] = kFALSE;
77     fPrintScope[iType] = kTRUE;
78     fPrintLocation[iType] = (iType == kDebug);  
79   }
80
81   // replace the previous instance by this one
82   if (fgInstance) delete fgInstance;
83   fgInstance = this;
84
85   SetHandleRootMessages(kTRUE);
86
87   // read the .rootrc settings
88   ReadEnvSettings();
89 }
90
91 //_____________________________________________________________________________
92 AliLog::~AliLog()
93 {
94 // destructor: clean up and reset instance pointer
95
96   if (fRepetitions > 0) PrintRepetitions();
97
98   for (Int_t i = 0; i < fModuleDebugLevels.GetEntriesFast(); i++) {
99     if (fModuleDebugLevels[i]) fModuleDebugLevels[i]->Delete();
100   }
101   fClassDebugLevels.Delete();
102   for (Int_t i = 0; i < fClassDebugLevels.GetEntriesFast(); i++) {
103     if (fClassDebugLevels[i]) fClassDebugLevels[i]->Delete();
104   }
105   fClassDebugLevels.Delete();
106
107   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
108     CloseFile(iType);
109   }
110   fflush(stderr);
111   fflush(stdout);
112
113   fgInstance = NULL;
114 }
115
116 //_____________________________________________________________________________
117 AliLog::AliLog(const AliLog& log) :
118   TObject(log),
119   fGlobalLogLevel(log.fGlobalLogLevel),
120   fModuleDebugLevels(log.fModuleDebugLevels),
121   fClassDebugLevels(log.fClassDebugLevels),
122   fPrintRepetitions(log.fPrintRepetitions),
123   fRepetitions(log.fRepetitions),
124   fLastType(log.fLastType),
125   fLastMessage(log.fLastMessage),
126   fLastModule(log.fLastModule),
127   fLastClassName(log.fLastClassName),
128   fLastFunction(log.fLastFunction),
129   fLastFile(log.fLastFile),
130   fLastLine(log.fLastLine)
131 {
132 // copy constructor
133
134   Fatal("AliLog", "copy constructor not implemented");
135 }
136
137 //_____________________________________________________________________________
138 AliLog& AliLog::operator = (const AliLog& /*log*/)
139 {
140 // assignment operator
141
142   Fatal("operator =", "assignment operator not implemented");
143   return *this;
144 }
145
146
147 //_____________________________________________________________________________
148 void AliLog::ReadEnvSettings()
149 {
150 // load settings from the root configuration file (.rootrc)
151 // and from environment variables
152
153   static const char* typeNames[kMaxType] = 
154     {"kFatal", "kError", "kWarning", "kInfo", "kDebug"};
155
156   // debug en- or disabling
157   if (gSystem->Getenv("LOG_NO_DEBUG")) {
158     fgDebugEnabled = kFALSE;
159   } else if (gEnv->Defined("AliRoot.AliLog.EnableDebug")) {
160     fgDebugEnabled = gEnv->GetValue("AliRoot.AliLog.EnableDebug", 
161                                     fgDebugEnabled);
162     AliInfo(Form("debug %sabled", ((fgDebugEnabled) ? "en" : "dis")));
163   }
164
165   // global log level
166   if (gEnv->Defined("AliRoot.AliLog.GlobalLogLevel")) {
167     const char* type = gEnv->GetValue("AliRoot.AliLog.GlobalLogLevel", "");
168     for (Int_t iType = kFatal; iType < kMaxType; iType++) {
169       if (strcmp(type, typeNames[iType]) == 0) fGlobalLogLevel = iType;
170     }
171     AliDebug(3, Form("global log level set to %d", fGlobalLogLevel));
172   }
173
174   // global debug level
175   if (gEnv->Defined("AliRoot.AliLog.GlobalDebugLevel")) {
176     Int_t level = gEnv->GetValue("AliRoot.AliLog.GlobalDebugLevel",
177                                  Int_t(fGlobalLogLevel - kDebugOffset));
178     if (level < -kDebugOffset) level = kDebugOffset;
179     fGlobalLogLevel = kDebugOffset + level;
180     AliDebug(3, Form("global debug level set to %d",
181                      fGlobalLogLevel - kDebugOffset));
182   }
183
184   // module debug level
185   if (gEnv->Defined("AliRoot.AliLog.ModuleDebugLevel")) {
186     TString levels = gEnv->GetValue("AliRoot.AliLog.ModuleDebugLevel", "");
187     char* p = const_cast<char*>(levels.Data());
188     while (const char* module = strtok(p, " ")) {
189       p = NULL;
190       char* pos = index(module, ':');
191       if (!pos) continue;
192       *(pos++) = '\0';
193       Int_t level = atoi(pos);
194       SetModuleDebugLevel(module, level);
195       AliDebug(3, Form("debug level for module %s set to %d", module, level));
196     }
197   }
198
199   // class debug level
200   if (gEnv->Defined("AliRoot.AliLog.ClassDebugLevel")) {
201     TString levels = gEnv->GetValue("AliRoot.AliLog.ClassDebugLevel", "");
202     char* p = const_cast<char*>(levels.Data());
203     while (const char* className = strtok(p, " ")) {
204       p = NULL;
205       char* pos = index(className, ':');
206       if (!pos) continue;
207       *(pos++) = '\0';
208       Int_t level = atoi(pos);
209       SetClassDebugLevel(className, level);
210       AliDebug(3, Form("debug level for class %s set to %d", 
211                        className, level));
212     }
213   }
214
215   // general output stream
216   if (gEnv->Defined("AliRoot.AliLog.Output")) {
217     TString stream = gEnv->GetValue("AliRoot.AliLog.Output", "Standard");
218     if (stream.CompareTo("standard", TString::kIgnoreCase) == 0) {
219       SetStandardOutput();
220       AliDebug(3, "output stream set to standard output for all types");
221     } else if (stream.CompareTo("error", TString::kIgnoreCase) == 0) {
222       SetErrorOutput();
223       AliDebug(3, "output stream set to error output for all types");
224     } else if (!stream.IsNull()) {
225       SetFileOutput(stream);
226       AliDebug(3, Form("output stream set to file %s for all types", 
227                        stream.Data()));
228     }
229   }
230
231   // individual output streams
232   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
233     TString name("AliRoot.AliLog.Output.");
234     name += &typeNames[iType][1];
235     if (gEnv->Defined(name)) {
236       TString stream = gEnv->GetValue(name, "Standard");
237       if (stream.CompareTo("standard", TString::kIgnoreCase) == 0) {
238         SetStandardOutput(EType(iType));
239         AliDebug(3, Form("output stream set to standard output for type %s",
240                          typeNames[iType]));
241       } else if (stream.CompareTo("error", TString::kIgnoreCase) == 0) {
242         SetErrorOutput(EType(iType));
243         AliDebug(3, Form("output stream set to error output for type %s",
244                          typeNames[iType]));
245       } else if (!stream.IsNull()) {
246         SetFileOutput(EType(iType), stream);
247         AliDebug(3, Form("output stream set to file %s for type %s", 
248                          stream.Data(), typeNames[iType]));
249       }
250     }
251   }
252
253   // handling of root error messages
254   if (gEnv->Defined("AliRoot.AliLog.HandleRootMessages")) {
255     Bool_t on = gEnv->GetValue("AliRoot.AliLog.HandleRootMessages", kTRUE);
256     SetHandleRootMessages(on);
257     AliDebug(3, Form("handling of root messages %sabled",
258                      ((on) ? "en" : "dis")));
259   }
260
261   // printout settings
262   static const char* settingNames[4] = 
263     {"Type", "Module", "Scope", "Location"};
264   Bool_t* settings[] = 
265     {fPrintType, fPrintModule, fPrintScope, fPrintLocation};
266   for (Int_t iSetting = 0; iSetting < 4; iSetting++) {
267     TString name("AliRoot.AliLog.Print");
268     name += settingNames[iSetting];
269     if (gEnv->Defined(name)) {
270       Bool_t on = gEnv->GetValue(name, settings[iSetting][0]);
271       for (Int_t iType = kFatal; iType < kMaxType; iType++) {
272         settings[iSetting][iType] = on;
273       }
274       AliDebug(3, Form("printing of %s %sabled for all types",
275                        settingNames[iSetting], ((on) ? "en" : "dis")));
276     }
277
278     for (Int_t iType = kFatal; iType < kMaxType; iType++) {
279       TString nameType = name + "." + &typeNames[iType][1];
280       if (gEnv->Defined(nameType)) {
281         Bool_t on = gEnv->GetValue(nameType, settings[iSetting][iType]);
282         settings[iSetting][iType] = on;
283         AliDebug(3, Form("printing of %s %sabled for type %s",
284                          settingNames[iSetting], ((on) ? "en" : "dis"),
285                          typeNames[iType]));
286       }
287     }
288   }
289
290   // repetition of messages
291   if (gEnv->Defined("AliRoot.AliLog.PrintRepetitions")) {
292     Bool_t on = gEnv->GetValue("AliRoot.AliLog.PrintRepetitions", kTRUE);
293     fPrintRepetitions = on;
294     AliDebug(3, Form("printing of message repetitions %sabled",
295                      ((on) ? "en" : "dis")));
296   }
297 }
298
299
300 //_____________________________________________________________________________
301 void AliLog::RootErrorHandler(Int_t level, Bool_t abort, 
302                               const char* location, const char* message)
303 {
304 // new error handler for messages from root
305
306   switch (level) {
307   case ::kFatal    : level = kFatal; break;
308   case ::kSysError :
309     DefaultErrorHandler(level, abort, location, message);
310     return;
311   case ::kBreak    :
312     DefaultErrorHandler(level, abort, location, message);
313     return;
314   case ::kError    : level = kError; break;
315   case ::kWarning  : level = kWarning; break;
316   case ::kInfo     : level = kInfo; break;
317   default          : level = kDebug; break;
318   }
319   AliLog::Message(level, message, "ROOT", NULL, location, NULL, 0);
320 }
321
322
323 //_____________________________________________________________________________
324 void AliLog::EnableDebug(Bool_t enabled)
325 {
326 // enable or disable debug output
327
328   fgDebugEnabled = enabled;
329 }
330
331 //_____________________________________________________________________________
332 void AliLog::SetGlobalLogLevel(EType type)
333 {
334 // set the global debug level
335
336   if (!fgInstance) new AliLog; 
337   fgInstance->fGlobalLogLevel = type;
338 }
339
340 //_____________________________________________________________________________
341 Int_t AliLog::GetGlobalLogLevel()
342 {
343 // get the global debug level
344
345   if (!fgInstance) new AliLog;
346   return fgInstance->fGlobalLogLevel;
347 }
348
349 //_____________________________________________________________________________
350 void AliLog::SetGlobalDebugLevel(Int_t level)
351 {
352 // set the global debug level
353
354   if (!fgInstance) new AliLog;
355   if (level < -kDebugOffset) level = -kDebugOffset;
356   fgInstance->fGlobalLogLevel = kDebugOffset + level;
357 }
358
359 //_____________________________________________________________________________
360 Int_t AliLog::GetGlobalDebugLevel()
361 {
362 // get the global debug level
363
364   if (!fgInstance) new AliLog;
365   return fgInstance->fGlobalLogLevel - kDebugOffset;
366 }
367
368 //_____________________________________________________________________________
369 void AliLog::SetModuleDebugLevel(const char* module, Int_t level)
370 {
371 // set the debug level for the given module
372
373   if (!module) return;
374   if (!fgInstance) new AliLog;
375   TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module);
376   if (!obj) {
377     obj = new TNamed(module, module);
378     fgInstance->fModuleDebugLevels.Add(obj);
379   }
380   level += kDebugOffset;
381   if (level < kFatal) level = kFatal;
382   obj->SetUniqueID(level);
383 }
384
385 //_____________________________________________________________________________
386 void AliLog::ClearModuleDebugLevel(const char* module)
387 {
388 // remove the setting of the debug level for the given module
389
390   if (!module) return;
391   if (!fgInstance) new AliLog;
392   TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module);
393   if (obj) delete fgInstance->fModuleDebugLevels.Remove(obj);
394 }
395
396 //_____________________________________________________________________________
397 void AliLog::SetClassDebugLevel(const char* className, Int_t level)
398 {
399 // set the debug level for the given class
400
401   if (!className) return;
402   if (!fgInstance) new AliLog;
403   TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
404   if (!obj) {
405     obj = new TNamed(className, className);
406     fgInstance->fClassDebugLevels.Add(obj);
407   }
408   level += kDebugOffset;
409   if (level < kFatal) level = kFatal;
410   obj->SetUniqueID(level);
411 }
412
413 //_____________________________________________________________________________
414 void AliLog::ClearClassDebugLevel(const char* className)
415 {
416 // remove the setting of the debug level for the given class
417
418   if (!className) return;
419   if (!fgInstance) new AliLog;
420   TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
421   if (obj) delete fgInstance->fClassDebugLevels.Remove(obj);
422 }
423
424
425 //_____________________________________________________________________________
426 void AliLog::SetStandardOutput()
427 {
428 // write all log messages to the standard output (stdout)
429
430   if (!fgInstance) new AliLog;
431   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
432     fgInstance->CloseFile(iType);
433     fgInstance->fOutputTypes[iType] = 0;
434   }
435 }
436
437 //_____________________________________________________________________________
438 void AliLog::SetStandardOutput(EType type)
439 {
440 // write log messages of the given type to the standard output (stdout)
441
442   if ((type < kFatal) || (type >= kMaxType)) return;
443   if (!fgInstance) new AliLog;
444   fgInstance->CloseFile(type);
445   fgInstance->fOutputTypes[type] = 0;
446 }
447
448 //_____________________________________________________________________________
449 void AliLog::SetErrorOutput()
450 {
451 // write all log messages to the error output (stderr)
452
453   if (!fgInstance) new AliLog;
454   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
455     fgInstance->CloseFile(iType);
456     fgInstance->fOutputTypes[iType] = 1;
457   }
458 }
459
460 //_____________________________________________________________________________
461 void AliLog::SetErrorOutput(EType type)
462 {
463 // write log messages of the given type to the error output (stderr)
464
465   if ((type < kFatal) || (type >= kMaxType)) return;
466   if (!fgInstance) new AliLog;
467   fgInstance->CloseFile(type);
468   fgInstance->fOutputTypes[type] = 1;
469 }
470
471 //_____________________________________________________________________________
472 void AliLog::SetFileOutput(const char* fileName)
473 {
474 // write all log messages to the given file
475
476   if (!fgInstance) new AliLog;
477   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
478     if ((fgInstance->fOutputTypes[iType] == 2) && 
479         (fgInstance->fFileNames[iType].CompareTo(fileName) != 0)) {
480       fgInstance->CloseFile(iType);
481     }
482     fgInstance->fOutputTypes[iType] = 2;
483     fgInstance->fFileNames[iType] = fileName;
484     fgInstance->fOutputFiles[iType] = NULL;
485     fgInstance->fOutputStreams[iType] = NULL;
486   }
487 }
488
489 //_____________________________________________________________________________
490 void AliLog::SetFileOutput(EType type, const char* fileName)
491 {
492 // write log messages of the given type to the given file
493
494   if ((type < kFatal) || (type >= kMaxType)) return;
495   if (!fgInstance) new AliLog;
496   if ((fgInstance->fOutputTypes[type] == 2) && 
497       (fgInstance->fFileNames[type].CompareTo(fileName) != 0)) {
498     fgInstance->CloseFile(type);
499   }
500   fgInstance->fOutputTypes[type] = 2;
501   fgInstance->fFileNames[type] = fileName;
502   fgInstance->fOutputFiles[type] = NULL;
503   fgInstance->fOutputStreams[type] = NULL;
504 }
505
506 //_____________________________________________________________________________
507 void AliLog::CloseFile(Int_t type)
508 {
509 // close the file for the given type if needed
510
511   if ((fOutputTypes[type] == 2) && fOutputFiles[type]) {
512     Bool_t closeFile = kTRUE;
513     for (Int_t iType = kFatal; iType < kMaxType; iType++) {
514       if ((iType != type) && (fOutputFiles[iType] == fOutputFiles[type])) {
515         closeFile = kFALSE;
516       }
517     }
518     if (closeFile) {
519       fclose(fOutputFiles[type]);
520       fOutputStreams[type]->close();
521       delete fOutputStreams[type];
522     }
523   }
524   fOutputFiles[type] = NULL;
525   fOutputStreams[type] = NULL;
526   fFileNames[type] = "";
527   fOutputTypes[type] = 0;
528 }
529
530 //_____________________________________________________________________________
531 FILE* AliLog::GetOutputStream(Int_t type)
532 {
533 // get the output stream for the given type of messages
534
535   if (type > kDebug) type = kDebug;
536   if (fOutputTypes[type] == 0) return stdout;
537   else if (fOutputTypes[type] == 1) return stderr;
538   else if (fOutputTypes[type] == 2) {
539     if (!fOutputFiles[type]) {
540       FILE* file = NULL;
541       ofstream* stream = NULL;
542       if (!fFileNames[type].IsNull()) {
543         for (Int_t iType = kFatal; iType < kMaxType; iType++) {
544           if ((iType != type) && 
545               (fFileNames[iType].CompareTo(fFileNames[type]) == 0) &&
546               fOutputFiles[iType]) {
547             file = fOutputFiles[iType];
548             stream = fOutputStreams[iType];
549             break;
550           }
551         }
552         if (!file) {
553           file = fopen(fFileNames[type], "a");
554           stream = new ofstream(fFileNames[type], ios::app);
555         }
556       }
557       fOutputFiles[type] = file;
558       fOutputStreams[type] = stream;
559       if (!file) CloseFile(type);
560     }
561     if (fOutputFiles[type]) return fOutputFiles[type];
562   }
563
564   return stdout;
565 }
566
567 //_____________________________________________________________________________
568 void AliLog::Flush()
569 {
570 // flush the output streams
571
572   if (!fgInstance) new AliLog;
573   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
574     if (fgInstance->fOutputFiles[iType]) {
575       fflush(fgInstance->fOutputFiles[iType]);
576       fgInstance->fOutputStreams[iType]->flush();
577     }
578   }
579   fflush(stderr);
580   fflush(stdout);
581 }
582
583
584 //_____________________________________________________________________________
585 void AliLog::SetHandleRootMessages(Bool_t on)
586 {
587 // enable or disable the handling of messages form root
588
589   if (!fgInstance) new AliLog;
590   if (on) {
591     SetErrorHandler(RootErrorHandler);
592   } else {
593     SetErrorHandler(DefaultErrorHandler);
594   }
595 }
596
597
598 //_____________________________________________________________________________
599 void AliLog::SetPrintType(Bool_t on)
600 {
601 // switch on or off the printing of the message type for all message types
602
603   if (!fgInstance) new AliLog;
604   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
605     fgInstance->fPrintType[iType] = on;
606   }
607 }
608
609 //_____________________________________________________________________________
610 void AliLog::SetPrintType(EType type, Bool_t on)
611 {
612 // switch on or off the printing of the message type for the given message type
613
614   if ((type < kFatal) || (type >= kMaxType)) return;
615   if (!fgInstance) new AliLog;
616   fgInstance->fPrintType[type] = on;
617 }
618
619 //_____________________________________________________________________________
620 void AliLog::SetPrintModule(Bool_t on)
621 {
622 // switch on or off the printing of the module for all message types
623
624   if (!fgInstance) new AliLog;
625   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
626     fgInstance->fPrintModule[iType] = on;
627   }
628 }
629
630 //_____________________________________________________________________________
631 void AliLog::SetPrintModule(EType type, Bool_t on)
632 {
633 // switch on or off the printing of the module for the given message type
634
635   if ((type < kFatal) || (type >= kMaxType)) return;
636   if (!fgInstance) new AliLog;
637   fgInstance->fPrintModule[type] = on;
638 }
639
640 //_____________________________________________________________________________
641 void AliLog::SetPrintScope(Bool_t on)
642 {
643 // switch on or off the printing of the scope/class name for all message types
644
645   if (!fgInstance) new AliLog;
646   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
647     fgInstance->fPrintScope[iType] = on;
648   }
649 }
650
651 //_____________________________________________________________________________
652 void AliLog::SetPrintScope(EType type, Bool_t on)
653 {
654 // switch on or off the printing of the scope/class name
655 // for the given message type
656
657   if ((type < kFatal) || (type >= kMaxType)) return;
658   if (!fgInstance) new AliLog;
659   fgInstance->fPrintScope[type] = on;
660 }
661
662 //_____________________________________________________________________________
663 void AliLog::SetPrintLocation(Bool_t on)
664 {
665 // switch on or off the printing of the file name and line number
666 // for all message types
667
668   if (!fgInstance) new AliLog;
669   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
670     fgInstance->fPrintLocation[iType] = on;
671   }
672 }
673
674 //_____________________________________________________________________________
675 void AliLog::SetPrintLocation(EType type, Bool_t on)
676 {
677 // switch on or off the printing of the file name and line number 
678 // for the given message type
679
680   if ((type < kFatal) || (type >= kMaxType)) return;
681   if (!fgInstance) new AliLog;
682   fgInstance->fPrintLocation[type] = on;
683 }
684
685
686 //_____________________________________________________________________________
687 void AliLog::SetPrintRepetitions(Bool_t on)
688 {
689 // switch on or off the printing of the number of repetitions of a message
690 // instead of repeating the same message
691
692   if (!fgInstance) new AliLog;
693   if (!on && (fgInstance->fRepetitions > 0)) fgInstance->PrintRepetitions();
694   fgInstance->fPrintRepetitions = on;
695 }
696
697
698 //_____________________________________________________________________________
699 void AliLog::WriteToFile(const char* name, Int_t option)
700 {
701 // write the log object with the given name and option to the current file
702
703   if (!fgInstance) new AliLog;
704   fgInstance->TObject::Write(name, option);
705 }
706
707
708 //_____________________________________________________________________________
709 UInt_t AliLog::GetLogLevel(const char* module, const char* className) const
710 {
711 // get the logging level for the given module and class
712
713   if (!fgInstance) new AliLog;
714   if (className) {
715     TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
716     if (obj) return obj->GetUniqueID();
717   }
718   if (module) {
719     TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module);
720     if (obj) return obj->GetUniqueID();
721   }
722   return fgInstance->fGlobalLogLevel;
723 }
724
725 //_____________________________________________________________________________
726 Int_t AliLog::GetDebugLevel(const char* module, const char* className)
727 {
728 // get the debug level for the given module and class
729
730   if (!fgInstance) new AliLog;
731   return fgInstance->GetLogLevel(module, className) - kDebugOffset;
732 }
733
734 //_____________________________________________________________________________
735 void AliLog::PrintMessage(UInt_t type, const char* message, 
736                           const char* module, const char* className,
737                           const char* function, const char* file, Int_t line)
738 {
739 // print the given message
740
741   // don't print the message if it is repeated
742   if (fPrintRepetitions &&
743       (fLastType == type) && 
744       (message && (fLastMessage.CompareTo(message) == 0)) &&
745       ((module && (fLastModule.CompareTo(module) == 0)) ||
746        (!module && fLastModule.IsNull())) &&
747       ((className && (fLastClassName.CompareTo(className) == 0)) ||
748        (!className && fLastClassName.IsNull())) &&
749       ((function && (fLastFunction.CompareTo(function) == 0)) ||
750        (!function && fLastFunction.IsNull()))&&
751       ((file && (fLastFile.CompareTo(file) == 0)) ||
752        (!file && fLastFile.IsNull())) &&
753       (fLastLine == line)) {
754     fRepetitions++;
755     return;
756   }
757
758   // print number of repetitions
759   if (fRepetitions > 0) PrintRepetitions();
760
761   // remember this message
762   fRepetitions = 0;
763   fLastType = type;
764   fLastMessage = message;
765   fLastModule = module;
766   fLastClassName = className;
767   fLastFunction = function;
768   fLastFile = file;
769   fLastLine = line;
770
771   // print the message
772   FILE* stream = GetOutputStream(type);
773   static const char* typeNames[kMaxType] = 
774     {"Fatal", "Error", "Warning", "Info", "Debug"};
775
776   if (fPrintType[type]) {
777     fprintf(stream, "%c-", typeNames[type][0]);
778   }
779   if (fPrintModule[type] && module) {
780     fprintf(stream, "%s/", module);
781   }
782   if (fPrintScope[type] && className) {
783     fprintf(stream, "%s::", className);
784   }
785   if (message) {
786     fprintf(stream, "%s: %s", function, message);
787   } else {
788     fprintf(stream, "%s", function);
789   }
790   if (fPrintLocation[type] && file) {
791     fprintf(stream, " (%s:%.0d)", file, line);
792   }
793   if (message) {
794     fprintf(stream, "\n");
795   } else {
796     fprintf(stream, ": ");
797   }
798 }
799
800 //_____________________________________________________________________________
801 void AliLog::PrintRepetitions()
802 {
803 // print number of repetitions
804
805   fprintf(GetOutputStream(fLastType), " <message repeated %d time%s>\n", 
806           fRepetitions, (fRepetitions > 1) ? "s" : "");
807 }
808
809 //_____________________________________________________________________________
810 void AliLog::Message(UInt_t level, const char* message, 
811                      const char* module, const char* className,
812                      const char* function, const char* file, Int_t line)
813 {
814 // print a log message
815
816   if (!fgInstance) new AliLog;
817
818   // get the message type
819   UInt_t type = level;
820   if (type >= kMaxType) type = kMaxType - 1;
821
822   // print the message if the debug level allows
823   if (level <= fgInstance->GetLogLevel(module, className)) {
824     fgInstance->PrintMessage(type, message, 
825                              module, className, function, file, line);
826   }
827
828   // abort in case of a fatal message
829   if (type == kFatal) {
830     delete fgInstance;
831     if (gSystem) {
832       gSystem->StackTrace();
833       gSystem->Abort();
834     } else {
835       ::abort();
836     }
837   }
838 }
839
840 //_____________________________________________________________________________
841 void AliLog::Debug(UInt_t level, const char* message, 
842                    const char* module, const char* className,
843                    const char* function, const char* file, Int_t line)
844 {
845 // print a debug message
846
847   if (level == 0) level = 1;
848   level += kDebugOffset;
849   Message(level, message, module, className, function, file, line);
850 }
851
852
853 //_____________________________________________________________________________
854 Int_t AliLog::RedirectStdoutTo(EType type, UInt_t level, const char* module, 
855                                const char* className, const char* function,
856                                const char* file, Int_t line, Bool_t print)
857 {
858 // redirect the standard output to the stream of the given type
859
860   if (!fgInstance) new AliLog;
861   return fgInstance->RedirectTo(stdout, type, level, module, className, 
862                                 function, file, line, print);
863 }
864
865 //_____________________________________________________________________________
866 Int_t AliLog::RedirectStderrTo(EType type, UInt_t level, const char* module, 
867                                const char* className, const char* function,
868                                const char* file, Int_t line, Bool_t print)
869 {
870 // redirect the standard error output to the stream of the given type
871
872   if (!fgInstance) new AliLog;
873   return fgInstance->RedirectTo(stderr, type, level, module, className, 
874                                 function, file, line, print);
875 }
876
877 //_____________________________________________________________________________
878 Int_t AliLog::RedirectTo(FILE* stream, EType type, UInt_t level, 
879                          const char* module, const char* className,
880                          const char* function, const char* file, Int_t line,
881                          Bool_t print)
882 {
883 // redirect the standard (error) output stream to the stream of the given type
884
885   // get the original file descriptor to be able to restore it later
886   Int_t original = dup(fileno(stream));
887   fflush(stream);
888
889   // flush the stream of the selected type
890   FILE* newStream = GetOutputStream(type);
891   fflush(newStream);
892
893   // redirect stream
894   if ((type == kDebug) && (level > 0)) level--;
895   if (type + level > GetLogLevel(module, className)) { // /dev/null
896     freopen("/dev/null", "a", stream);
897   } else if (fOutputTypes[type] == 0) {         // stdout
898     if (stream != stdout) dup2(fileno(stdout), fileno(stream));
899   } else if (fOutputTypes[type] == 1) {         // stderr
900     if (stream != stderr) dup2(fileno(stderr), fileno(stream));
901   } else if (fOutputTypes[type] == 2) {         // file
902     freopen(fFileNames[type], "a", stream);
903   }
904
905   // print information
906   if (print) {
907     PrintMessage(type, NULL, module, className, function, file, line);
908     fflush(newStream);
909   }
910
911   return original;
912 }
913
914 //_____________________________________________________________________________
915 void AliLog::RestoreStdout(Int_t original)
916 {
917 // restore the standard output
918
919   fflush(stdout);
920   dup2(original, fileno(stdout));  
921   close(original);
922 }
923
924 //_____________________________________________________________________________
925 void AliLog::RestoreStderr(Int_t original)
926 {
927 // restore the standard error output
928
929   fflush(stderr);
930   dup2(original, fileno(stderr));  
931   close(original);
932 }
933
934
935 //_____________________________________________________________________________
936 ostream& AliLog::Stream(EType type, UInt_t level,
937                         const char* module, const char* className,
938                         const char* function, const char* file, Int_t line)
939 {
940 // get the stream object for the given output type
941
942   if (!fgInstance) new AliLog;
943   return fgInstance->GetStream(type, level, module, className, 
944                                function, file, line);
945 }
946
947 //_____________________________________________________________________________
948 ostream& AliLog::GetStream(EType type, UInt_t level,
949                            const char* module, const char* className,
950                            const char* function, const char* file, Int_t line)
951 {
952 // get the stream object for the given output type
953
954   if ((type == kDebug) && (level > 0)) level--;
955   Bool_t noOutput = (type + level > GetLogLevel(module, className));
956
957   if (!noOutput) {
958     PrintMessage(type, NULL, module, className, function, file, line);
959   }
960   fflush(GetOutputStream(type));
961
962   static ofstream nullStream("/dev/null");
963   if (noOutput) {
964     return nullStream;
965   } else if (fOutputTypes[type] == 0) {
966     return cout;
967   } else if (fOutputTypes[type] == 1) {
968     return cerr;
969   } else if (fOutputTypes[type] == 2) {
970     return *fOutputStreams[type];
971   }
972
973   return nullStream;
974 }
975