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