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