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