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