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