]>
Commit | Line | Data |
---|---|---|
6ab674bd | 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 <TError.h> | |
35 | #include <TNamed.h> | |
36 | #include <TSystem.h> | |
37 | ||
38 | #include "AliLog.h" | |
39 | ||
40 | ClassImp(AliLog) | |
41 | ||
42 | ||
43 | AliLog* AliLog::fgInstance = NULL; | |
44 | ||
45 | Bool_t AliLog::fgDebugEnabled = kTRUE; | |
46 | ||
47 | ||
48 | //_____________________________________________________________________________ | |
49 | AliLog::AliLog() : | |
50 | TObject(), | |
51 | fGlobalLogLevel(kInfo), | |
52 | fModuleDebugLevels(), | |
53 | fClassDebugLevels() | |
54 | { | |
55 | // default constructor: set default values | |
56 | ||
57 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
58 | fOutputTypes[iType] = 0; | |
59 | fFileNames[iType] = ""; | |
60 | fOutputFiles[iType] = NULL; | |
61 | ||
62 | fPrintType[iType] = kTRUE; | |
63 | fPrintModule[iType] = kFALSE; | |
64 | fPrintScope[iType] = kTRUE; | |
65 | fPrintLocation[iType] = (iType == kDebug); | |
66 | } | |
67 | ||
68 | SetHandleRootMessages(kTRUE); | |
69 | ||
70 | // replace the previous instance by this one | |
71 | if (fgInstance) delete fgInstance; | |
72 | fgInstance = this; | |
73 | } | |
74 | ||
75 | //_____________________________________________________________________________ | |
76 | AliLog::~AliLog() | |
77 | { | |
78 | // destructor: clean up and reset instance pointer | |
79 | ||
80 | for (Int_t i = 0; i < fModuleDebugLevels.GetEntriesFast(); i++) { | |
81 | if (fModuleDebugLevels[i]) fModuleDebugLevels[i]->Delete(); | |
82 | } | |
83 | fClassDebugLevels.Delete(); | |
84 | for (Int_t i = 0; i < fClassDebugLevels.GetEntriesFast(); i++) { | |
85 | if (fClassDebugLevels[i]) fClassDebugLevels[i]->Delete(); | |
86 | } | |
87 | fClassDebugLevels.Delete(); | |
88 | ||
89 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
90 | CloseFile(iType); | |
91 | } | |
92 | fflush(stderr); | |
93 | fflush(stdout); | |
94 | ||
95 | fgInstance = NULL; | |
96 | } | |
97 | ||
98 | //_____________________________________________________________________________ | |
99 | AliLog::AliLog(const AliLog& log) : | |
100 | TObject(log) | |
101 | { | |
102 | // copy constructor | |
103 | ||
104 | Fatal("AliLog", "copy constructor not implemented"); | |
105 | } | |
106 | ||
107 | //_____________________________________________________________________________ | |
108 | AliLog& AliLog::operator = (const AliLog& /*log*/) | |
109 | { | |
110 | // assignment operator | |
111 | ||
112 | Fatal("operator =", "assignment operator not implemented"); | |
113 | return *this; | |
114 | } | |
115 | ||
116 | ||
117 | //_____________________________________________________________________________ | |
118 | void AliLog::RootErrorHandler(Int_t level, Bool_t abort, | |
119 | const char* location, const char* message) | |
120 | { | |
121 | // new error handler for messages from root | |
122 | ||
123 | switch (level) { | |
124 | case ::kFatal : level = kFatal; break; | |
125 | case ::kSysError : | |
126 | DefaultErrorHandler(level, abort, location, message); | |
127 | return; | |
128 | case ::kBreak : | |
129 | DefaultErrorHandler(level, abort, location, message); | |
130 | return; | |
131 | case ::kError : level = kError; break; | |
132 | case ::kWarning : level = kWarning; break; | |
133 | case ::kInfo : level = kInfo; break; | |
134 | default : level = kDebug; break; | |
135 | } | |
136 | AliLog::Message(level, message, "ROOT", NULL, location, NULL, 0); | |
137 | } | |
138 | ||
139 | ||
140 | //_____________________________________________________________________________ | |
141 | void AliLog::EnableDebug(Bool_t enabled) | |
142 | { | |
143 | // enable or disable debug output | |
144 | ||
145 | fgDebugEnabled = enabled; | |
146 | } | |
147 | ||
148 | //_____________________________________________________________________________ | |
149 | void AliLog::SetGlobalLogLevel(EType type) | |
150 | { | |
151 | // set the global debug level | |
152 | ||
153 | if (!fgInstance) new AliLog; | |
154 | fgInstance->fGlobalLogLevel = type; | |
155 | } | |
156 | ||
157 | //_____________________________________________________________________________ | |
158 | Int_t AliLog::GetGlobalLogLevel() | |
159 | { | |
160 | // get the global debug level | |
161 | ||
162 | if (!fgInstance) new AliLog; | |
163 | return fgInstance->fGlobalLogLevel; | |
164 | } | |
165 | ||
166 | //_____________________________________________________________________________ | |
167 | void AliLog::SetGlobalDebugLevel(Int_t level) | |
168 | { | |
169 | // set the global debug level | |
170 | ||
171 | if (!fgInstance) new AliLog; | |
172 | if (level < -kDebugOffset) level = -kDebugOffset; | |
173 | fgInstance->fGlobalLogLevel = kDebugOffset + level; | |
174 | } | |
175 | ||
176 | //_____________________________________________________________________________ | |
177 | Int_t AliLog::GetGlobalDebugLevel() | |
178 | { | |
179 | // get the global debug level | |
180 | ||
181 | if (!fgInstance) new AliLog; | |
182 | return fgInstance->fGlobalLogLevel - kDebugOffset; | |
183 | } | |
184 | ||
185 | //_____________________________________________________________________________ | |
186 | void AliLog::SetModuleDebugLevel(const char* module, Int_t level) | |
187 | { | |
188 | // set the debug level for the given module | |
189 | ||
190 | if (!module) return; | |
191 | if (!fgInstance) new AliLog; | |
192 | TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module); | |
193 | if (!obj) { | |
194 | obj = new TNamed(module, module); | |
195 | fgInstance->fModuleDebugLevels.Add(obj); | |
196 | } | |
197 | level += kDebugOffset; | |
198 | if (level < kFatal) level = kFatal; | |
199 | obj->SetUniqueID(level); | |
200 | } | |
201 | ||
202 | //_____________________________________________________________________________ | |
203 | void AliLog::ClearModuleDebugLevel(const char* module) | |
204 | { | |
205 | // remove the setting of the debug level for the given module | |
206 | ||
207 | if (!module) return; | |
208 | if (!fgInstance) new AliLog; | |
209 | TObject* obj = fgInstance->fModuleDebugLevels.FindObject(module); | |
210 | if (obj) delete fgInstance->fModuleDebugLevels.Remove(obj); | |
211 | } | |
212 | ||
213 | //_____________________________________________________________________________ | |
214 | void AliLog::SetClassDebugLevel(const char* className, Int_t level) | |
215 | { | |
216 | // set the debug level for the given class | |
217 | ||
218 | if (!className) return; | |
219 | if (!fgInstance) new AliLog; | |
220 | TObject* obj = fgInstance->fClassDebugLevels.FindObject(className); | |
221 | if (!obj) { | |
222 | obj = new TNamed(className, className); | |
223 | fgInstance->fClassDebugLevels.Add(obj); | |
224 | } | |
225 | level += kDebugOffset; | |
226 | if (level < kFatal) level = kFatal; | |
227 | obj->SetUniqueID(level); | |
228 | } | |
229 | ||
230 | //_____________________________________________________________________________ | |
231 | void AliLog::ClearClassDebugLevel(const char* className) | |
232 | { | |
233 | // remove the setting of the debug level for the given class | |
234 | ||
235 | if (!className) return; | |
236 | if (!fgInstance) new AliLog; | |
237 | TObject* obj = fgInstance->fClassDebugLevels.FindObject(className); | |
238 | if (obj) delete fgInstance->fClassDebugLevels.Remove(obj); | |
239 | } | |
240 | ||
241 | ||
242 | //_____________________________________________________________________________ | |
243 | void AliLog::SetStandardOutput() | |
244 | { | |
245 | // write all log messages to the standard output (stdout) | |
246 | ||
247 | if (!fgInstance) new AliLog; | |
248 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
249 | fgInstance->CloseFile(iType); | |
250 | fgInstance->fOutputTypes[iType] = 0; | |
251 | } | |
252 | } | |
253 | ||
254 | //_____________________________________________________________________________ | |
255 | void AliLog::SetStandardOutput(EType type) | |
256 | { | |
257 | // write log messages of the given type to the standard output (stdout) | |
258 | ||
259 | if ((type < kFatal) || (type >= kMaxType)) return; | |
260 | if (!fgInstance) new AliLog; | |
261 | fgInstance->CloseFile(type); | |
262 | fgInstance->fOutputTypes[type] = 0; | |
263 | } | |
264 | ||
265 | //_____________________________________________________________________________ | |
266 | void AliLog::SetErrorOutput() | |
267 | { | |
268 | // write all log messages to the error output (stderr) | |
269 | ||
270 | if (!fgInstance) new AliLog; | |
271 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
272 | fgInstance->CloseFile(iType); | |
273 | fgInstance->fOutputTypes[iType] = 1; | |
274 | } | |
275 | } | |
276 | ||
277 | //_____________________________________________________________________________ | |
278 | void AliLog::SetErrorOutput(EType type) | |
279 | { | |
280 | // write log messages of the given type to the error output (stderr) | |
281 | ||
282 | if ((type < kFatal) || (type >= kMaxType)) return; | |
283 | if (!fgInstance) new AliLog; | |
284 | fgInstance->CloseFile(type); | |
285 | fgInstance->fOutputTypes[type] = 1; | |
286 | } | |
287 | ||
288 | //_____________________________________________________________________________ | |
289 | void AliLog::SetFileOutput(const char* fileName) | |
290 | { | |
291 | // write all log messages to the given file | |
292 | ||
293 | if (!fgInstance) new AliLog; | |
294 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
295 | if ((fgInstance->fOutputTypes[iType] = 2) && | |
296 | (fgInstance->fFileNames[iType].CompareTo(fileName) != 0)) { | |
297 | fgInstance->CloseFile(iType); | |
298 | } | |
299 | fgInstance->fOutputTypes[iType] = 2; | |
300 | fgInstance->fFileNames[iType] = fileName; | |
301 | fgInstance->fOutputFiles[iType] = NULL; | |
302 | } | |
303 | } | |
304 | ||
305 | //_____________________________________________________________________________ | |
306 | void AliLog::SetFileOutput(EType type, const char* fileName) | |
307 | { | |
308 | // write log messages of the given type to the given file | |
309 | ||
310 | if ((type < kFatal) || (type >= kMaxType)) return; | |
311 | if (!fgInstance) new AliLog; | |
312 | if ((fgInstance->fOutputTypes[type] = 2) && | |
313 | (fgInstance->fFileNames[type].CompareTo(fileName) != 0)) { | |
314 | fgInstance->CloseFile(type); | |
315 | } | |
316 | fgInstance->fOutputTypes[type] = 2; | |
317 | fgInstance->fFileNames[type] = fileName; | |
318 | fgInstance->fOutputFiles[type] = NULL; | |
319 | } | |
320 | ||
321 | //_____________________________________________________________________________ | |
322 | void AliLog::CloseFile(Int_t type) | |
323 | { | |
324 | // close the file for the given type if needed | |
325 | ||
326 | if ((fOutputTypes[type] == 2) && fOutputFiles[type]) { | |
327 | Bool_t closeFile = kTRUE; | |
328 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
329 | if ((iType != type) && (fOutputFiles[iType] == fOutputFiles[type])) { | |
330 | closeFile = kFALSE; | |
331 | } | |
332 | } | |
333 | if (closeFile) fclose(fOutputFiles[type]); | |
334 | } | |
335 | fOutputFiles[type] = NULL; | |
336 | fFileNames[type] = ""; | |
337 | fOutputTypes[type] = 0; | |
338 | } | |
339 | ||
340 | //_____________________________________________________________________________ | |
341 | FILE* AliLog::GetOutputStream(Int_t type) | |
342 | { | |
343 | // get the output stream for the given type of messages | |
344 | ||
345 | if (fOutputTypes[type] == 0) return stdout; | |
346 | else if (fOutputTypes[type] == 1) return stderr; | |
347 | else if (fOutputTypes[type] == 2) { | |
348 | if (!fOutputFiles[type]) { | |
349 | FILE* file = NULL; | |
350 | if (!fFileNames[type].IsNull()) { | |
351 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
352 | if ((iType != type) && | |
353 | (fFileNames[iType].CompareTo(fFileNames[type]) == 0) && | |
354 | fOutputFiles[iType]) { | |
355 | file = fOutputFiles[iType]; | |
356 | break; | |
357 | } | |
358 | } | |
359 | if (!file) file = fopen(fFileNames[type], "a"); | |
360 | } | |
361 | fOutputFiles[type] = file; | |
362 | if (!file) CloseFile(type); | |
363 | } | |
364 | if (fOutputFiles[type]) return fOutputFiles[type]; | |
365 | } | |
366 | ||
367 | return stdout; | |
368 | } | |
369 | ||
370 | //_____________________________________________________________________________ | |
371 | void AliLog::Flush() | |
372 | { | |
373 | // flush the output streams | |
374 | ||
375 | if (!fgInstance) new AliLog; | |
376 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
377 | if (fgInstance->fOutputFiles[iType]) { | |
378 | fflush(fgInstance->fOutputFiles[iType]); | |
379 | } | |
380 | } | |
381 | fflush(stderr); | |
382 | fflush(stdout); | |
383 | } | |
384 | ||
385 | ||
386 | //_____________________________________________________________________________ | |
387 | void AliLog::SetHandleRootMessages(Bool_t on) | |
388 | { | |
389 | // enable or disable the handling of messages form root | |
390 | ||
391 | if (on) { | |
392 | SetErrorHandler(RootErrorHandler); | |
393 | } else { | |
394 | SetErrorHandler(DefaultErrorHandler); | |
395 | } | |
396 | } | |
397 | ||
398 | ||
399 | //_____________________________________________________________________________ | |
400 | void AliLog::SetPrintType(Bool_t on) | |
401 | { | |
402 | // switch on or off the printing of the message type for all message types | |
403 | ||
404 | if (!fgInstance) new AliLog; | |
405 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
406 | fgInstance->fPrintType[iType] = on; | |
407 | } | |
408 | } | |
409 | ||
410 | //_____________________________________________________________________________ | |
411 | void AliLog::SetPrintType(EType type, Bool_t on) | |
412 | { | |
413 | // switch on or off the printing of the message type for the given message type | |
414 | ||
415 | if ((type < kFatal) || (type >= kMaxType)) return; | |
416 | if (!fgInstance) new AliLog; | |
417 | fgInstance->fPrintType[type] = on; | |
418 | } | |
419 | ||
420 | //_____________________________________________________________________________ | |
421 | void AliLog::SetPrintModule(Bool_t on) | |
422 | { | |
423 | // switch on or off the printing of the module for all message types | |
424 | ||
425 | if (!fgInstance) new AliLog; | |
426 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
427 | fgInstance->fPrintModule[iType] = on; | |
428 | } | |
429 | } | |
430 | ||
431 | //_____________________________________________________________________________ | |
432 | void AliLog::SetPrintModule(EType type, Bool_t on) | |
433 | { | |
434 | // switch on or off the printing of the module for the given message type | |
435 | ||
436 | if ((type < kFatal) || (type >= kMaxType)) return; | |
437 | if (!fgInstance) new AliLog; | |
438 | fgInstance->fPrintModule[type] = on; | |
439 | } | |
440 | ||
441 | //_____________________________________________________________________________ | |
442 | void AliLog::SetPrintScope(Bool_t on) | |
443 | { | |
444 | // switch on or off the printing of the scope/class name for all message types | |
445 | ||
446 | if (!fgInstance) new AliLog; | |
447 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
448 | fgInstance->fPrintScope[iType] = on; | |
449 | } | |
450 | } | |
451 | ||
452 | //_____________________________________________________________________________ | |
453 | void AliLog::SetPrintScope(EType type, Bool_t on) | |
454 | { | |
455 | // switch on or off the printing of the scope/class name | |
456 | // for the given message type | |
457 | ||
458 | if ((type < kFatal) || (type >= kMaxType)) return; | |
459 | if (!fgInstance) new AliLog; | |
460 | fgInstance->fPrintScope[type] = on; | |
461 | } | |
462 | ||
463 | //_____________________________________________________________________________ | |
464 | void AliLog::SetPrintLocation(Bool_t on) | |
465 | { | |
466 | // switch on or off the printing of the file name and line number | |
467 | // for all message types | |
468 | ||
469 | if (!fgInstance) new AliLog; | |
470 | for (Int_t iType = kFatal; iType < kMaxType; iType++) { | |
471 | fgInstance->fPrintLocation[iType] = on; | |
472 | } | |
473 | } | |
474 | ||
475 | //_____________________________________________________________________________ | |
476 | void AliLog::SetPrintLocation(EType type, Bool_t on) | |
477 | { | |
478 | // switch on or off the printing of the file name and line number | |
479 | // for the given message type | |
480 | ||
481 | if ((type < kFatal) || (type >= kMaxType)) return; | |
482 | if (!fgInstance) new AliLog; | |
483 | fgInstance->fPrintLocation[type] = on; | |
484 | } | |
485 | ||
486 | ||
487 | //_____________________________________________________________________________ | |
488 | void AliLog::Write(const char* name, Int_t option) | |
489 | { | |
490 | // write the log object with the given name and option to the current file | |
491 | ||
492 | if (!fgInstance) new AliLog; | |
493 | fgInstance->TObject::Write(name, option); | |
494 | } | |
495 | ||
496 | ||
497 | //_____________________________________________________________________________ | |
498 | UInt_t AliLog::GetLogLevel(const char* module, const char* className) const | |
499 | { | |
500 | // get the logging level for the given module and class | |
501 | ||
502 | if (!fgInstance) new AliLog; | |
503 | TObject* obj = fgInstance->fClassDebugLevels.FindObject(className); | |
504 | if (obj) return obj->GetUniqueID(); | |
505 | obj = fgInstance->fModuleDebugLevels.FindObject(module); | |
506 | if (obj) return obj->GetUniqueID(); | |
507 | return fgInstance->fGlobalLogLevel; | |
508 | } | |
509 | ||
510 | //_____________________________________________________________________________ | |
511 | Int_t AliLog::GetDebugLevel(const char* module, const char* className) | |
512 | { | |
513 | // get the debug level for the given module and class | |
514 | ||
515 | if (!fgInstance) new AliLog; | |
516 | return fgInstance->GetLogLevel(module, className) - kDebugOffset; | |
517 | } | |
518 | ||
519 | //_____________________________________________________________________________ | |
520 | void AliLog::Message(UInt_t level, const char* message, | |
521 | const char* module, const char* className, | |
522 | const char* function, const char* file, Int_t line) | |
523 | { | |
524 | // print a log message | |
525 | ||
526 | if (!fgInstance) new AliLog; | |
527 | ||
528 | // get the message type | |
529 | static const char* typeNames[kMaxType] = | |
530 | {"Fatal", "Error", "Warning", "Info", "Debug"}; | |
531 | UInt_t type = level; | |
532 | if (type >= kMaxType) type = kMaxType - 1; | |
533 | ||
534 | // print the message if the debug level allows | |
535 | if (level <= fgInstance->GetLogLevel(module, className)) { | |
536 | if (fgInstance->fPrintType[type]) { | |
537 | fprintf(fgInstance->GetOutputStream(type), "%s in ", typeNames[type]); | |
538 | } | |
539 | fprintf(fgInstance->GetOutputStream(type), "<"); | |
540 | if (fgInstance->fPrintModule[type] && module) { | |
541 | fprintf(fgInstance->GetOutputStream(type), "%s/", module); | |
542 | } | |
543 | if (fgInstance->fPrintScope[type] && className) { | |
544 | fprintf(fgInstance->GetOutputStream(type), "%s::", className); | |
545 | } | |
546 | fprintf(fgInstance->GetOutputStream(type), "%s>: %s", function, message); | |
547 | if (fgInstance->fPrintLocation[type] && file) { | |
548 | fprintf(fgInstance->GetOutputStream(type), " (%s:%.0d)", file, line); | |
549 | } | |
550 | fprintf(fgInstance->GetOutputStream(type), "\n"); | |
551 | } | |
552 | ||
553 | // abort in case of a fatal message | |
554 | if (type == kFatal) { | |
555 | delete fgInstance; | |
556 | if (gSystem) { | |
557 | gSystem->StackTrace(); | |
558 | gSystem->Abort(); | |
559 | } else { | |
560 | ::abort(); | |
561 | } | |
562 | } | |
563 | } | |
564 | ||
565 | //_____________________________________________________________________________ | |
566 | void AliLog::Debug(UInt_t level, const char* message, | |
567 | const char* module, const char* className, | |
568 | const char* function, const char* file, Int_t line) | |
569 | { | |
570 | // print a debug message | |
571 | ||
572 | if (level == 0) level = 1; | |
573 | level += kDebugOffset; | |
574 | Message(level, message, module, className, function, file, line); | |
575 | } |