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