]> git.uio.no Git - u/mrichter/AliRoot.git/blob - STEER/STEERBase/AliLog.cxx
Reading friends in analysis framework inside HLT
[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   if (gSystem->Getenv("ALIROOT_FORCE_COREDUMP")){
382     EnableCoreDump(kTRUE);
383   }
384
385 }
386
387
388 //_____________________________________________________________________________
389 void AliLog::RootErrorHandler(Int_t level, Bool_t abort, 
390                               const char* location, const char* message)
391 {
392 // new error handler for messages from root
393
394   switch (level)
395   {
396   case ::kFatal    : level = kFatal; break;
397   case ::kSysError :
398     DefaultErrorHandler(level, abort, location, message);
399     return;
400   case ::kBreak    :
401     DefaultErrorHandler(level, abort, location, message);
402     return;
403   case ::kError    : level = kError; break;
404   case ::kWarning  : level = kWarning; break;
405   case ::kInfo     : level = kInfo; break;
406   default          : level = kDebug; break;
407   }
408   AliLog::Message(level, message, "ROOT", NULL, location, NULL, 0);
409 }
410
411
412 // DEPRECATED: USE A CONFIGURATION FILE INSTEAD
413 //_____________________________________________________________________________
414 void AliLog::EnableDebug(Bool_t enabled)
415 {
416 // enable or disable debug output
417
418   fgDebugEnabled = enabled;
419 }
420
421 void AliLog::EnableCoreDump(Bool_t enabled)
422 {
423 // enable or disable debug output
424
425   fgCoreEnabled = enabled;
426   gSystem->ResetSignal(kSigFloatingException,enabled);
427   gSystem->ResetSignal(kSigSegmentationViolation,enabled);
428   if (enabled) printf("Core dump enabled\n");
429   else { 
430     printf("Core dump disabled\n");
431   }
432 }
433
434
435
436 //_____________________________________________________________________________
437 void AliLog::SetGlobalLogLevel(EType_t type)
438 {
439 // set the global debug level
440
441   // TO BE DELETED
442   if (!fgInstance) new AliLog; 
443   fgInstance->fGlobalLogLevel = type;
444 }
445
446 //_____________________________________________________________________________
447 Int_t AliLog::GetGlobalLogLevel()
448 {
449 // get the global debug level
450
451   if (!fgInstance) new AliLog;
452   return fgInstance->fGlobalLogLevel;
453 }
454
455 //_____________________________________________________________________________
456 void AliLog::SetGlobalDebugLevel(Int_t level)
457 {
458 // set the global debug level
459
460   if (!fgInstance) new AliLog;
461   if (level < -kDebugOffset) level = -kDebugOffset;
462   fgInstance->fGlobalLogLevel = kDebugOffset + level;
463 }
464
465 //_____________________________________________________________________________
466 Int_t AliLog::GetGlobalDebugLevel()
467 {
468 // get the global debug level
469
470   if (!fgInstance) new AliLog;
471   return fgInstance->fGlobalLogLevel - kDebugOffset;
472 }
473
474 //_____________________________________________________________________________
475 void AliLog::SetModuleDebugLevel(const char* module, Int_t level)
476 {
477 // set the debug level for the given module
478
479   if (!module) return;
480   if (!fgInstance) new AliLog;
481   TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module);
482   if (!obj) {
483     obj = new TNamed(module, module);
484     fgInstance->fModuleDebugLevels.Add(obj);
485   }
486   level += kDebugOffset;
487   if (level < kFatal) level = kFatal;
488   obj->SetUniqueID(level);
489 }
490
491 //_____________________________________________________________________________
492 void AliLog::ClearModuleDebugLevel(const char* module)
493 {
494 // remove the setting of the debug level for the given module
495
496   if (!module) return;
497   if (!fgInstance) new AliLog;
498   TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module);
499   if (obj) delete fgInstance->fModuleDebugLevels.Remove(obj);
500 }
501
502 //_____________________________________________________________________________
503 void AliLog::SetClassDebugLevel(const char* className, Int_t level)
504 {
505 // set the debug level for the given class
506
507   if (!className) return;
508   if (!fgInstance) new AliLog;
509   TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
510   if (!obj) {
511     obj = new TNamed(className, className);
512     fgInstance->fClassDebugLevels.Add(obj);
513   }
514   level += kDebugOffset;
515   if (level < kFatal) level = kFatal;
516   obj->SetUniqueID(level);
517 }
518
519 //_____________________________________________________________________________
520 void AliLog::ClearClassDebugLevel(const char* className)
521 {
522 // remove the setting of the debug level for the given class
523
524   if (!className) return;
525   if (!fgInstance) new AliLog;
526   TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
527   if (obj) delete fgInstance->fClassDebugLevels.Remove(obj);
528 }
529
530
531 //_____________________________________________________________________________
532 void AliLog::SetStandardOutput()
533 {
534 // write all log messages to the standard output (stdout)
535
536   if (!fgInstance) new AliLog;
537   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
538     fgInstance->CloseFile(iType);
539     fgInstance->fOutputTypes[iType] = 0;
540   }
541 }
542
543 //_____________________________________________________________________________
544 void AliLog::SetStandardOutput(EType_t type)
545 {
546 // write log messages of the given type to the standard output (stdout)
547
548   if ((type < kFatal) || (type >= kMaxType)) return;
549   if (!fgInstance) new AliLog;
550   fgInstance->CloseFile(type);
551   fgInstance->fOutputTypes[type] = 0;
552 }
553
554 //_____________________________________________________________________________
555 void AliLog::SetErrorOutput()
556 {
557 // write all log messages to the error output (stderr)
558
559   if (!fgInstance) new AliLog;
560   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
561     fgInstance->CloseFile(iType);
562     fgInstance->fOutputTypes[iType] = 1;
563   }
564 }
565
566 //_____________________________________________________________________________
567 void AliLog::SetErrorOutput(EType_t type)
568 {
569 // write log messages of the given type to the error output (stderr)
570
571   if ((type < kFatal) || (type >= kMaxType)) return;
572   if (!fgInstance) new AliLog;
573   fgInstance->CloseFile(type);
574   fgInstance->fOutputTypes[type] = 1;
575 }
576
577 //_____________________________________________________________________________
578 void AliLog::SetFileOutput(const char* fileName)
579 {
580 // write all log messages to the given file
581
582   if (!fgInstance) new AliLog;
583   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
584     if ((fgInstance->fOutputTypes[iType] == 2) && 
585         (fgInstance->fFileNames[iType].CompareTo(fileName) != 0)) {
586       fgInstance->CloseFile(iType);
587     }
588     fgInstance->fOutputTypes[iType] = 2;
589     fgInstance->fFileNames[iType] = fileName;
590     fgInstance->fOutputFiles[iType] = NULL;
591     fgInstance->fOutputStreams[iType] = NULL;
592   }
593 }
594
595 //_____________________________________________________________________________
596 void AliLog::SetFileOutput(EType_t type, const char* fileName)
597 {
598 // write log messages of the given type to the given file
599
600   if ((type < kFatal) || (type >= kMaxType)) return;
601   if (!fgInstance) new AliLog;
602   if ((fgInstance->fOutputTypes[type] == 2) && 
603       (fgInstance->fFileNames[type].CompareTo(fileName) != 0)) {
604     fgInstance->CloseFile(type);
605   }
606   fgInstance->fOutputTypes[type] = 2;
607   fgInstance->fFileNames[type] = fileName;
608   fgInstance->fOutputFiles[type] = NULL;
609   fgInstance->fOutputStreams[type] = NULL;
610 }
611
612 //_____________________________________________________________________________
613 void AliLog::CloseFile(Int_t type)
614 {
615 // close the file for the given type if needed
616
617   if ((fOutputTypes[type] == 2) && fOutputFiles[type]) {
618     Bool_t closeFile = kTRUE;
619     for (Int_t iType = kFatal; iType < kMaxType; iType++) {
620       if ((iType != type) && (fOutputFiles[iType] == fOutputFiles[type])) {
621         closeFile = kFALSE;
622       }
623     }
624     if (closeFile) {
625       fclose(fOutputFiles[type]);
626       ofstream* stream=reinterpret_cast<ofstream*>(fOutputStreams[type]);
627       stream->close();
628       delete fOutputStreams[type];
629     }
630   }
631   fOutputFiles[type] = NULL;
632   fOutputStreams[type] = NULL;
633   fFileNames[type] = "";
634   fOutputTypes[type] = 0;
635 }
636
637 //_____________________________________________________________________________
638 FILE* AliLog::GetOutputStream(Int_t type)
639 {
640 // get the output stream for the given type of messages
641
642   if (type > kDebug) type = kDebug;
643   if (fOutputTypes[type] == 0) return stdout;
644   else if (fOutputTypes[type] == 1) return stderr;
645   else if (fOutputTypes[type] == 2) {
646     if (!fOutputFiles[type]) {
647       FILE* file = NULL;
648       ostream* stream = NULL;
649       if (!fFileNames[type].IsNull()) {
650         for (Int_t iType = kFatal; iType < kMaxType; iType++) {
651           if ((iType != type) && 
652               (fFileNames[iType].CompareTo(fFileNames[type]) == 0) &&
653               fOutputFiles[iType]) {
654             file = fOutputFiles[iType];
655             stream = fOutputStreams[iType];
656             break;
657           }
658         }
659         if (!file) {
660           file = fopen(fFileNames[type], "a");
661           stream = new ofstream(fFileNames[type], ios::app);
662         }
663       }
664       fOutputFiles[type] = file;
665       fOutputStreams[type] = stream;
666       if (!file) CloseFile(type);
667     }
668     if (fOutputFiles[type]) return fOutputFiles[type];
669   }
670
671   return stdout;
672 }
673
674 //_____________________________________________________________________________
675 void AliLog::Flush()
676 {
677 // flush the output streams
678
679   if (!fgInstance) new AliLog;
680   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
681     if (fgInstance->fOutputFiles[iType]) {
682       fflush(fgInstance->fOutputFiles[iType]);
683       fgInstance->fOutputStreams[iType]->flush();
684     }
685   }
686   fflush(stderr);
687   fflush(stdout);
688 }
689
690
691 //_____________________________________________________________________________
692 void AliLog::SetHandleRootMessages(Bool_t on)
693 {
694 // enable or disable the handling of messages form root
695
696   if (!fgInstance) new AliLog;
697   if (on) {
698     SetErrorHandler(RootErrorHandler);
699   } else {
700     SetErrorHandler(DefaultErrorHandler);
701   }
702 }
703
704
705 //_____________________________________________________________________________
706 void AliLog::SetPrintType(Bool_t on)
707 {
708 // switch on or off the printing of the message type for all message types
709
710   if (!fgInstance) new AliLog;
711   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
712     fgInstance->fPrintType[iType] = on;
713   }
714 }
715
716 //_____________________________________________________________________________
717 void AliLog::SetPrintType(EType_t type, Bool_t on)
718 {
719 // switch on or off the printing of the message type for the given message type
720
721   if ((type < kFatal) || (type >= kMaxType)) return;
722   if (!fgInstance) new AliLog;
723   fgInstance->fPrintType[type] = on;
724 }
725
726 //_____________________________________________________________________________
727 void AliLog::SetPrintModule(Bool_t on)
728 {
729 // switch on or off the printing of the module for all message types
730
731   if (!fgInstance) new AliLog;
732   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
733     fgInstance->fPrintModule[iType] = on;
734   }
735 }
736
737 //_____________________________________________________________________________
738 void AliLog::SetPrintModule(EType_t type, Bool_t on)
739 {
740 // switch on or off the printing of the module for the given message type
741
742   if ((type < kFatal) || (type >= kMaxType)) return;
743   if (!fgInstance) new AliLog;
744   fgInstance->fPrintModule[type] = on;
745 }
746
747 //_____________________________________________________________________________
748 void AliLog::SetPrintScope(Bool_t on)
749 {
750 // switch on or off the printing of the scope/class name for all message types
751
752   if (!fgInstance) new AliLog;
753   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
754     fgInstance->fPrintScope[iType] = on;
755   }
756 }
757
758 //_____________________________________________________________________________
759 void AliLog::SetPrintScope(EType_t type, Bool_t on)
760 {
761 // switch on or off the printing of the scope/class name
762 // for the given message type
763
764   if ((type < kFatal) || (type >= kMaxType)) return;
765   if (!fgInstance) new AliLog;
766   fgInstance->fPrintScope[type] = on;
767 }
768
769 //_____________________________________________________________________________
770 void AliLog::SetPrintLocation(Bool_t on)
771 {
772 // switch on or off the printing of the file name and line number
773 // for all message types
774
775   if (!fgInstance) new AliLog;
776   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
777     fgInstance->fPrintLocation[iType] = on;
778   }
779 }
780
781 //_____________________________________________________________________________
782 void AliLog::SetPrintLocation(EType_t type, Bool_t on)
783 {
784 // switch on or off the printing of the file name and line number 
785 // for the given message type
786
787   if ((type < kFatal) || (type >= kMaxType)) return;
788   if (!fgInstance) new AliLog;
789   fgInstance->fPrintLocation[type] = on;
790 }
791
792
793 //_____________________________________________________________________________
794 void AliLog::SetPrintRepetitions(Bool_t on)
795 {
796 // switch on or off the printing of the number of repetitions of a message
797 // instead of repeating the same message
798
799   if (!fgInstance) new AliLog;
800   if (!on && (fgInstance->fRepetitions > 0)) fgInstance->PrintRepetitions();
801   fgInstance->fPrintRepetitions = on;
802 }
803
804
805 //_____________________________________________________________________________
806 void AliLog::WriteToFile(const char* name, Int_t option)
807 {
808 // write the log object with the given name and option to the current file
809
810   if (!fgInstance) new AliLog;
811   fgInstance->TObject::Write(name, option);
812 }
813
814
815 //_____________________________________________________________________________
816 UInt_t AliLog::GetLogLevel(const char* module, const char* className) const
817 {
818 // get the logging level for the given module and class
819
820   if (!fgInstance) new AliLog;
821   if (className) {
822     TObject* obj = fgInstance->fClassDebugLevels.FindObject(className);
823     if (obj) return obj->GetUniqueID();
824   }
825   if (module) {
826     TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module);
827     if (obj) return obj->GetUniqueID();
828   }
829   return fgInstance->fGlobalLogLevel;
830 }
831
832 //_____________________________________________________________________________
833 Int_t AliLog::GetDebugLevel(const char* module, const char* className)
834 {
835 // get the debug level for the given module and class
836
837   if (!fgInstance) new AliLog;
838   return fgInstance->GetLogLevel(module, className) - kDebugOffset;
839 }
840
841 //_____________________________________________________________________________
842 void AliLog::PrintMessage(UInt_t type, const char* message, 
843                           const char* module, const char* className,
844                           const char* function, const char* file, Int_t line)
845 {
846 // print the given message
847
848   // don't print the message if it is repeated
849   if (fPrintRepetitions &&
850       (fLastType == type) && 
851       (message && (fLastMessage.CompareTo(message) == 0)) &&
852       ((module && (fLastModule.CompareTo(module) == 0)) ||
853        (!module && fLastModule.IsNull())) &&
854       ((className && (fLastClassName.CompareTo(className) == 0)) ||
855        (!className && fLastClassName.IsNull())) &&
856       ((function && (fLastFunction.CompareTo(function) == 0)) ||
857        (!function && fLastFunction.IsNull()))&&
858       ((file && (fLastFile.CompareTo(file) == 0)) ||
859        (!file && fLastFile.IsNull())) &&
860       (fLastLine == line)) {
861     fRepetitions++;
862     return;
863   }
864
865   // print number of repetitions
866   if (fRepetitions > 0) PrintRepetitions();
867
868   // remember this message
869   fRepetitions = 0;
870   fLastType = type;
871   fLastMessage = message;
872   fLastModule = module;
873   fLastClassName = className;
874   fLastFunction = function;
875   fLastFile = file;
876   fLastLine = line;
877
878   // print the message
879   FILE* stream = GetOutputStream(type);
880   static const char* typeNames[kMaxType] = 
881     {"Fatal", "Error", "Warning", "Info", "Debug"};
882
883   if (fPrintType[type]) {
884     PrintString(type, stream, "%c-", typeNames[type][0]);
885   }
886   if (fPrintModule[type] && module) {
887     PrintString(type, stream, "%s/", module);
888   }
889   if (fPrintScope[type] && className) {
890     PrintString(type, stream, "%s::", className);
891   }
892   if (message) {
893     PrintString(type, stream, "%s: %s", function, message);
894   } else {
895     PrintString(type, stream, "%s", function);
896   }
897   if (fPrintLocation[type] && file) {
898     PrintString(type, stream, " (%s:%.0d)", file, line);
899   }
900   if (message) {
901     PrintString(type, stream, "\n");
902   } else {
903     PrintString(type, stream, ": ");
904   }
905   if (fCallBacks[type]) (*(fCallBacks[type]))((EType_t)type, NULL);
906 }
907
908 //_____________________________________________________________________________
909 void AliLog::PrintRepetitions()
910 {
911 // print number of repetitions
912
913   PrintString(fLastType, GetOutputStream(fLastType), " <message repeated %d time%s>\n", 
914           fRepetitions, (fRepetitions > 1) ? "s" : "");
915   if (fCallBacks[fLastType]) (*(fCallBacks[fLastType]))((EType_t)fLastType, NULL);
916 }
917
918 //_____________________________________________________________________________
919 void AliLog::Message(UInt_t level, const char* message, 
920                      const char* module, const char* className,
921                      const char* function, const char* file, Int_t line)
922 {
923 // print a log message
924
925   if (!fgInstance) new AliLog;
926
927   // get the message type
928   UInt_t type = level;
929   if (type >= kMaxType) type = kMaxType - 1;
930
931   // print the message if the debug level allows
932   if (level <= fgInstance->GetLogLevel(module, className)) {
933     fgInstance->PrintMessage(type, message, 
934                              module, className, function, file, line);
935   }
936
937   // abort in case of a fatal message
938   if (type == kFatal) {
939     delete fgInstance;
940     if (gSystem) {
941       gSystem->StackTrace();
942       if (fgCoreEnabled) MakeCoreDump("core.AliRoot");
943       gSystem->Abort();
944     } else {
945       if (fgCoreEnabled) MakeCoreDump("core.AliRoot");
946       ::abort();
947     }
948   }
949 }
950
951
952
953 //_____________________________________________________________________________
954 void AliLog::Debug(UInt_t level, const char* message, 
955                    const char* module, const char* className,
956                    const char* function, const char* file, Int_t line)
957 {
958 // print a debug message
959
960   if (level == 0) level = 1;
961   level += kDebugOffset;
962   Message(level, message, module, className, function, file, line);
963 }
964
965
966 //_____________________________________________________________________________
967 Int_t AliLog::RedirectStdoutTo(EType_t type, UInt_t level, const char* module, 
968                                const char* className, const char* function,
969                                const char* file, Int_t line, Bool_t print)
970 {
971 // redirect the standard output to the stream of the given type
972
973   if (!fgInstance) new AliLog;
974   return fgInstance->RedirectTo(stdout, type, level, module, className, 
975                                 function, file, line, print);
976 }
977
978 //_____________________________________________________________________________
979 Int_t AliLog::RedirectStderrTo(EType_t type, UInt_t level, const char* module, 
980                                const char* className, const char* function,
981                                const char* file, Int_t line, Bool_t print)
982 {
983 // redirect the standard error output to the stream of the given type
984
985   if (!fgInstance) new AliLog;
986   return fgInstance->RedirectTo(stderr, type, level, module, className, 
987                                 function, file, line, print);
988 }
989
990 //_____________________________________________________________________________
991 Int_t AliLog::RedirectTo(FILE* stream, EType_t type, UInt_t level, 
992                          const char* module, const char* className,
993                          const char* function, const char* file, Int_t line,
994                          Bool_t print)
995 {
996 // redirect the standard (error) output stream to the stream of the given type
997
998   // get the original file descriptor to be able to restore it later
999   Int_t original = dup(fileno(stream));
1000   fflush(stream);
1001
1002   // flush the stream of the selected type
1003   FILE* newStream = GetOutputStream(type);
1004   fflush(newStream);
1005
1006   // redirect stream
1007   if ((type == kDebug) && (level > 0)) level--;
1008   if (type + level > GetLogLevel(module, className)) { // /dev/null
1009     if(!freopen("/dev/null", "a", stream)) AliWarning("Cannot reopen /dev/null");
1010   } else if (fOutputTypes[type] == 0) {         // stdout
1011     if (stream != stdout) dup2(fileno(stdout), fileno(stream));
1012   } else if (fOutputTypes[type] == 1) {         // stderr
1013     if (stream != stderr) dup2(fileno(stderr), fileno(stream));
1014   } else if (fOutputTypes[type] == 2) {         // file
1015     if(!freopen(fFileNames[type], "a", stream)) AliWarning(Form("Cannot reopen %s",fFileNames[type].Data()));
1016   } else if (fOutputTypes[type] == 3) {         // external C++ stream
1017     // redirection is not possible for external C++ streams
1018   }
1019
1020   // print information
1021   if (print) {
1022     PrintMessage(type, NULL, module, className, function, file, line);
1023     fflush(newStream);
1024   }
1025
1026   return original;
1027 }
1028
1029 //_____________________________________________________________________________
1030 void AliLog::RestoreStdout(Int_t original)
1031 {
1032 // restore the standard output
1033
1034   fflush(stdout);
1035   dup2(original, fileno(stdout));  
1036   close(original);
1037 }
1038
1039 //_____________________________________________________________________________
1040 void AliLog::RestoreStderr(Int_t original)
1041 {
1042 // restore the standard error output
1043
1044   fflush(stderr);
1045   dup2(original, fileno(stderr));  
1046   close(original);
1047 }
1048
1049
1050 //_____________________________________________________________________________
1051 ostream& AliLog::Stream(EType_t type, UInt_t level,
1052                         const char* module, const char* className,
1053                         const char* function, const char* file, Int_t line)
1054 {
1055 // get the stream object for the given output type
1056
1057   if (!fgInstance) new AliLog;
1058   return fgInstance->GetStream(type, level, module, className, 
1059                                function, file, line);
1060 }
1061
1062 //_____________________________________________________________________________
1063 ostream& AliLog::GetStream(EType_t type, UInt_t level,
1064                            const char* module, const char* className,
1065                            const char* function, const char* file, Int_t line)
1066 {
1067 // get the stream object for the given output type
1068
1069   if ((type == kDebug) && (level > 0)) level--;
1070   Bool_t noOutput = (type + level > GetLogLevel(module, className));
1071
1072   if (!noOutput) {
1073     PrintMessage(type, NULL, module, className, function, file, line);
1074   }
1075   fflush(GetOutputStream(type));
1076
1077   static ofstream nullStream("/dev/null");
1078   if (noOutput) {
1079     return nullStream;
1080   } else if (fOutputTypes[type] == 0) {
1081     return cout;
1082   } else if (fOutputTypes[type] == 1) {
1083     return cerr;
1084   } else if (fOutputTypes[type] == 2) {
1085     return *fOutputStreams[type];
1086   } else if (fOutputTypes[type] == 3) {
1087     return *fOutputStreams[type];
1088   }
1089
1090   return nullStream;
1091 }
1092
1093 void  AliLog::SetStreamOutput(ostream* stream)
1094 {
1095   // set an external stream as target for log messages of all types
1096   // the external stream is completely handled by the caller, the
1097   // AliLog class just writes to it
1098
1099   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
1100     SetStreamOutput((AliLog::EType_t)iType, stream);
1101   }
1102 }
1103
1104 void  AliLog::SetStreamOutput(EType_t type, ostream* stream)
1105 {
1106   // set an external stream as target for log messages of the given type
1107   // the external stream is completely handled by the caller, the
1108   // AliLog class just writes to it
1109
1110   if ((type < kFatal) || (type >= kMaxType)) return;
1111   if (!fgInstance) new AliLog;
1112   if (fgInstance->fOutputTypes[type] == 2) {
1113     fgInstance->CloseFile(type);
1114   }
1115   fgInstance->fOutputTypes[type] = 3;
1116   fgInstance->fFileNames[type] = "";
1117   fgInstance->fOutputFiles[type] = NULL;
1118   fgInstance->fOutputStreams[type] = stream;
1119 }
1120
1121 void  AliLog::SetLogNotification(AliLogNotification pCallBack)
1122 {
1123   // set a notification callback function for log messages of all types
1124
1125   for (Int_t iType = kFatal; iType < kMaxType; iType++) {
1126     SetLogNotification((AliLog::EType_t)iType, pCallBack);
1127   }
1128 }
1129
1130 void  AliLog::SetLogNotification(EType_t type, AliLogNotification pCallBack)
1131 {
1132   // set a notifications call back function for log messages of all types
1133   // the callback fuction is invoced whenever an output was written
1134   // Note: does not work for c++ streamer classes, the external stream
1135   // has to handle this diectly (e.g. custom implementation of endl)
1136
1137   if ((type < kFatal) || (type >= kMaxType)) return;
1138   if (!fgInstance) new AliLog;
1139   fgInstance->fCallBacks[type]=pCallBack;
1140 }
1141
1142 void  AliLog::PrintString(Int_t type, FILE* stream, const char* format, ...)
1143 {
1144   // this is the general method to print a log message using variadac args
1145   // to the FILE* like (C - like) streams, e.g. stdout, stderr, or files
1146   // opened by fopen.
1147   // Only in case of an external c++ ostream type output, the message is
1148   // written to that stream and the notifictaion callback is called.
1149   // The message is printed by a normal vfprintf function otherwise
1150
1151   if (format==NULL) return;
1152   
1153   va_list ap;
1154   va_start(ap, format);
1155   if (fOutputTypes[type] != 3) {
1156     if (stream!=NULL) {
1157       vfprintf(stream, format, ap);
1158     }
1159   } else {
1160     // build the string and write everthing to the corresponding ostream
1161     TString fmt(format);
1162     TArrayC tgt(fmt.Length()*10); // just take a number
1163 #ifdef R__VA_COPY
1164     va_list bap;
1165     R__VA_COPY(bap, ap);
1166 #else
1167 #warning definition of R__VA_COPY has disappeared
1168 #endif //R__VA_COPY
1169
1170     Int_t iResult=0;
1171     while (1) {
1172       iResult=vsnprintf(tgt.GetArray(), tgt.GetSize(), format, ap);
1173       if (iResult==-1) {
1174         iResult=tgt.GetSize()*2;
1175       } else if (iResult<tgt.GetSize()) {
1176         break;
1177       }
1178 #ifdef R__VA_COPY
1179       if (iResult<10000) {
1180         tgt.Set(iResult+1);
1181         va_end(ap);
1182         R__VA_COPY(ap, bap);
1183       } else
1184 #endif //R__VA_COPY 
1185       {
1186         tgt[tgt.GetSize()-1]=0;
1187         break;
1188       }
1189     }
1190 #ifdef R__VA_COPY
1191     va_end(bap);
1192 #endif //R__VA_COPY
1193
1194     if (fOutputStreams[type]) {
1195       *(fOutputStreams[type]) << tgt.GetArray();
1196     }
1197   }
1198   va_end(ap);
1199 }
1200
1201
1202 void AliLog::MakeCoreDump(const char *fout){
1203   //
1204   // Functionality to make a program snapshot 
1205   //   gcore - Generate a core file for a running process 
1206   //   gcore dmake a current snapshot, program can continue further
1207   //   We assum that gcore is installed
1208   //   for details see:  man gcore
1209   //
1210   // Example use - make default core file for current process:  AliLog::MakeCoreDump(0)
1211   //
1212   //
1213   // Automatic core dump creation in case of the AliFatal can be specified using
1214   // static void  EnableCoreDump(Bool_t enabled);
1215   // Core dump is created in addition to the stack trace ()  
1216   // marian.ivanov@cern.ch
1217   //
1218   if (!gSystem) return;
1219   printf("AliLog::MakeCoreDump\n");
1220   if (fout){
1221     gSystem->Exec(Form("gcore -o %s  %d",fout, gSystem->GetPid()));
1222   }else{
1223     gSystem->Exec(Form("gcore   %d", gSystem->GetPid()));
1224   }
1225 }