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