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