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