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