source: trunk/MagicSoft/Mars/mbase/MLog.cc@ 9043

Last change on this file since 9043 was 8965, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 25.7 KB
Line 
1/* ======================================================================== *\
2! $Name: not supported by cvs2svn $:$Id: MLog.cc,v 1.61 2008-06-16 14:58:27 tbretz Exp $
3! --------------------------------------------------------------------------
4!
5! *
6! * This file is part of MARS, the MAGIC Analysis and Reconstruction
7! * Software. It is distributed to you in the hope that it can be a useful
8! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
9! * It is distributed WITHOUT ANY WARRANTY.
10! *
11! * Permission to use, copy, modify and distribute this software and its
12! * documentation for any purpose is hereby granted without fee,
13! * provided that the above copyright notice appear in all copies and
14! * that both that copyright notice and this permission notice appear
15! * in supporting documentation. It is provided "as is" without express
16! * or implied warranty.
17! *
18!
19!
20! Author(s): Thomas Bretz, 12/2000 <mailto:tbretz@astro.uni-wuerzburg.de>
21!
22! Copyright: MAGIC Software Development, 2000-2006
23!
24!
25\* ======================================================================== */
26
27//////////////////////////////////////////////////////////////////////////////
28//
29// MLog
30//
31// This is what we call the logging-system.
32//
33// It is derived from the C++ streaming classes and can handle our
34// logging. The log output can be redirected to stdout, stderr, any other
35// stream or a root window.
36//
37// There is a global log-instance which you can use like cout, id is gLog.
38// A log-instance of your choice (gLog by default) is destributed to all
39// Task which are used in an eventloop, so that you can redirect the output
40// of one eventloop to where you want..
41//
42// The MLog stream has the advantage, that it can be used like the common
43// C++ streams (for example cout). It can redirect the stream to different
44// outputs (console, file, GUI) if necessary at the same time.
45//
46// It supports different debug levels. The debug level of the current
47// stream contents is set by SetDebugLevel, the output level of the
48// current stream can be set by SetOutputLevel.
49//
50// The header file MLogManip.h contains so called manipulators (like flush
51// or setw from iomanip.h) which can manipulate these levels from within
52// stream, for example:
53// gLog << debug(3) << "Hallo World " << endl;
54// sets the debug level of the following stream to 3
55//
56// edev(), ddev() can be used to enable/disable an output device from
57// within the stream. The enumerations are defined in MLog::_flags
58//
59// Commonly used abbreviations are also defined:
60// dbginf Prints source file name and line number. Used for output
61// which people may like to look up in the code
62// all Is streamed to the output in any case. Used for outputs
63// which are requested by the user (eg TObject::Print)
64// err Should be used for fatal errors which stops the current
65// processing, eg:
66// gLog << err << "ERROR: TObject::Copy - Stopped" << endl;
67// warn Warning means an error occured, but it is not clear whether
68// this results further procesing or not.
69// inf Informs the user about what's going on. Mostly usefull for
70// debugging, but in general not necessary at all.
71// dbg Use this for your private purpose to mark something as debug
72// output. This is _not_ ment to be persistent!
73//
74// If your console is capable of ANSI colors the stream is displayed
75// in several colors:
76// all: default
77// err: red
78// warn: yellow/brown
79// inf: green
80// dbg: blue (and all other levels)
81//
82// If you have a dark background on your console you might want to set
83// an environment variable, eg:
84// export MARSDEFINES=-DHAVE_DARKBACKGROUND
85// and recompile MLog.
86//
87// If your console can display it also 'underline' can be used. This
88// underlines a text till the next 'endl', eg:
89// gLog << underline << "This is important!" << endl;
90//
91// To switch off ANSI support call: SetNoColors()
92//
93// gLog is a global stream defined like cout or cerr
94//
95//////////////////////////////////////////////////////////////////////////////
96#include "MLog.h"
97
98#include <stdlib.h> // mkstemp
99
100#include <fstream>
101#include <iomanip>
102
103#include <TROOT.h> // gROOT->GetListOfCleanups()
104#include <TSystem.h>
105
106#ifdef _REENTRANT
107#include <TMutex.h>
108#endif
109#include <TGTextView.h>
110
111#include <TEnv.h> // gEnv (ErrorHandler)
112#include <TError.h> // TError (SetErrorHandler)
113
114#include "MArgs.h"
115#include "MTime.h"
116#include "MParContainer.h"
117
118#include "MLogHtml.h"
119#include "MLogManip.h" // inf,warn,err (MLog::ErrorHandler)
120
121ClassImp(MLog);
122
123using namespace std;
124
125#undef DEBUG
126//#define DEBUG
127
128
129// root 3.02:
130// check for TObjectWarning, TObject::Info, gErrorIgnoreLevel
131
132const char MLog::kESC = '\033'; // (char)27
133const char *const MLog::kEsc = "\033[";
134const char *const MLog::kReset = "\033[0m";
135const char *const MLog::kRed = "\033[31m";
136const char *const MLog::kGreen = "\033[32m";
137#ifdef HAVE_DARKBACKGROUND
138const char *const MLog::kYellow = "\033[33m\033[1m";
139#else
140const char *const MLog::kYellow = "\033[33m";
141#endif
142const char *const MLog::kBlue = "\033[34m";
143const char *const MLog::kUnderline = "\033[4m";
144const char *const MLog::kBlink = "\033[5m";
145const char *const MLog::kBright = "\033[1m";
146const char *const MLog::kDark = "\033[2m";
147
148//
149// This is the definition of the global log facility
150//
151MLog gLog;
152
153// --------------------------------------------------------------------------
154//
155// this strange usage of an unbufferd buffer is a workaround
156// to make it work on Alpha and Linux!
157//
158void MLog::Init()
159{
160 //
161 // Creat drawing semaphore
162 //
163#ifdef _REENTRANT
164 fMuxGui = new TMutex;
165 fMuxStream = new TMutex;
166#endif
167
168 fPlugins = new TList;
169 gROOT->GetListOfCleanups()->Add(fPlugins);
170 fPlugins->SetBit(kMustCleanup);
171
172 setp(&fBuffer, &fBuffer+1);
173 *this << '\0';
174}
175
176// --------------------------------------------------------------------------
177//
178// default constructor which initializes the streamer and sets the device
179// which is used for the output (i)
180//
181MLog::MLog(int i) : ostream(this), fPPtr(fBase), fEPtr(fBase+fgBufferSize), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(i), fIsNull(kFALSE), fOut(NULL), fOutAllocated(kFALSE), fGui(NULL), fNumLines(0)
182{
183 Init();
184}
185
186// --------------------------------------------------------------------------
187//
188// default constructor which initializes the streamer and sets the given
189// ofstream as the default output device
190//
191MLog::MLog(ofstream &sout) : ostream(this), fPPtr(fBase), fEPtr(fBase+fgBufferSize), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(eFile), fIsNull(kFALSE), fOut(&sout), fOutAllocated(kFALSE), fGui(NULL), fNumLines(0)
192{
193 Init();
194}
195
196// --------------------------------------------------------------------------
197//
198// default constructor which initializes the streamer and sets the given
199// TGTextView as the default output device
200//
201MLog::MLog(TGTextView &sout) : ostream(this), fPPtr(fBase), fEPtr(fBase+fgBufferSize), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(eGui), fOut(NULL), fOutAllocated(kFALSE), fGui(&sout), fNumLines(0)
202{
203 Init();
204}
205
206// --------------------------------------------------------------------------
207//
208// default constructor which initializes the streamer and opens a file with
209// the given name. Dependend on the flag the file is set as output device
210// or not.
211//
212MLog::MLog(const char *fname, int flag) : ostream(this), fPPtr(fBase), fEPtr(fBase+fgBufferSize), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(eFile), fIsNull(kFALSE), fGui(NULL), fNumLines(0)
213{
214 Init();
215
216 AllocateFile(fname);
217 CheckFlag(eFile, flag);
218}
219
220// --------------------------------------------------------------------------
221//
222// Destructor, destroying the gui mutex.
223//
224MLog::~MLog()
225{
226 DeallocateFile();
227
228#ifdef DEBUG
229 TIter Next(fPlugins);
230 TObject *o=0;
231 while ((o=Next()))
232 {
233 cout << "Delete: " << o->GetName() << std::flush;
234 cout << " [" << o->ClassName() << "]" << endl;
235 delete o;
236 }
237
238 cout << "Delete: fPlugins " << fPlugins << "..." << std::flush;
239#endif
240
241 delete fPlugins;
242#ifdef DEBUG
243 cout << "done." << endl;
244#endif
245
246#ifdef _REENTRANT
247 delete fMuxStream;
248 delete fMuxGui;
249#endif
250}
251
252// --------------------------------------------------------------------------
253//
254// copyt constructor
255//
256/*
257MLog::MLog(MLog const& log)
258{
259// fOutputLevel = log.fOutputLevel;
260// fDebugLevel = log.fDebugLevel;
261// fDevice = log.fDevice;
262}
263*/
264
265void MLog::Underline()
266{
267 if (fIsNull)
268 return;
269
270 SetBit(kIsUnderlined);
271
272 fPlugins->R__FOR_EACH(MLogPlugin, Underline)();
273
274 if (TestBit(eNoColors))
275 return;
276
277 if (fDevice&eStdout)
278 cout << kUnderline;
279
280 if (fDevice&eStderr)
281 cerr << kUnderline;
282}
283
284void MLog::Output(ostream &sout, int len)
285{
286 if (!TestBit(eNoColors))
287 switch (fOutputLevel)
288 {
289 // do not output reset. Otherwise we reset underline in 0-mode
290 // case 1: out << MLog::kReset; break; // all
291 case 0: break; // all = background color
292 case 1: sout << MLog::kRed; break; // err
293 case 2: sout << MLog::kYellow; break; // warn
294 case 3: // inf
295 case 4: // inf2
296 case 5: sout << MLog::kGreen; break; // inf3
297 default: sout << MLog::kBlue; break; // all others (dbg)
298 }
299
300 if (len>0)
301 {
302 // Check for EOL
303 const Int_t endline = fBase[len-1]=='\n' ? 1 : 0;
304 // output text to screen (without trailing '\n')
305 sout << TString(fBase, len-endline);
306 // reset colors if working with colors
307 if (!TestBit(eNoColors))
308 sout << kReset;
309 // output EOL of check found EOL
310 if (endline)
311 {
312 sout << '\n';
313 // Check whether text was underlined
314 if (TestBit(kIsUnderlined) && TestBit(eNoColors))
315 {
316 sout << setw(len-1) << setfill('-') << "" << "\n";
317 ResetBit(kIsUnderlined);
318 }
319 }
320 }
321 sout.flush();
322}
323
324void MLog::AddGuiLine(const TString &line)
325{
326 // add a new TString* to the array of gui lines
327 TString **newstr = new TString*[fNumLines+1];
328 memcpy(newstr, fGuiLines, fNumLines*sizeof(TString*));
329 if (fNumLines>0)
330 delete [] fGuiLines;
331 fGuiLines = newstr;
332
333 // add Gui line as last line of array
334 fGuiLines[fNumLines++] = new TString(line);
335}
336
337// --------------------------------------------------------------------------
338//
339// This is the function which writes the stream physically to a device.
340// If you want to add a new device this must be done here.
341//
342void MLog::WriteBuffer()
343{
344 //
345 // restart writing to the buffer at its first char
346 //
347 const int len = fPPtr - fBase;
348
349 fPPtr = fBase;
350
351 if (fIsNull)
352 return;
353
354 if (fDevice&eStdout)
355 Output(cout, len);
356
357 if (fDevice&eStderr)
358 Output(cerr, len);
359
360 if (fDevice&eFile && fOut)
361 fOut->write(fBase, len);
362
363 fPlugins->R__FOR_EACH(MLogPlugin, SetColor)(fOutputLevel);
364 fPlugins->R__FOR_EACH(MLogPlugin, WriteBuffer)(fBase, len);
365
366 if (fDevice&eGui && fGui)
367 {
368 // check whether the current text was flushed or endl'ed
369 const Int_t endline = fBase[len-1]=='\n' ? 1 : 0;
370
371 // for the gui remove trailing characters ('\n' or '\0')
372 fBase[len-endline]='\0';
373
374 // add new text to line storage
375 fGuiLine += fBase;
376
377 if (endline)
378 {
379 AddGuiLine(fGuiLine);
380 fGuiLine = "";
381
382 // Check whether text should be underlined
383 if (endline && TestBit(kIsUnderlined))
384 {
385 AddGuiLine("");
386 fGuiLines[fNumLines-1]->Append('-', fGuiLines[fNumLines-2]->Length());
387 ResetBit(kIsUnderlined);
388 }
389 }
390 }
391}
392
393void MLog::UpdateGui()
394{
395 if (fNumLines==0)
396 return;
397
398 // lock mutex
399 if (!LockUpdate("UpdateGui"))
400 {
401 Warning("UpdateGui", "Execution skipped");
402 return;
403 }
404
405 TGText &txt=*fGui->GetText();
406
407 // copy lines to TGListBox
408 for (int i=0; i<fNumLines; i++)
409 {
410 // Replace all tabs by 7 white spaces
411 fGuiLines[i]->ReplaceAll("\t", " ");
412 txt.InsText(TGLongPosition(0, txt.RowCount()), *fGuiLines[i]);
413 delete fGuiLines[i];
414 }
415 delete [] fGuiLines;
416
417 fNumLines=0;
418
419 // cut text box top 1000 lines
420 // while (txt.RowCount()>1000)
421 // txt.DelLine(1);
422
423 // show last entry
424 fGui->Layout();
425 fGui->SetVsbPosition(txt.RowCount()-1);
426
427 // tell a main loop, that list box contents have changed
428 fGui->SetBit(kHasChanged);
429
430 // release mutex
431 UnLockUpdate("UpdateGui");
432}
433
434bool MLog::LockUpdate(const char *msg)
435{
436#ifdef _REENTRANT
437 if (fMuxGui->Lock()==13)
438 {
439 Info("LockUpdate", "%s - mutex is already locked by this thread\n", msg);
440 return false;
441 }
442#endif
443 return true;
444}
445
446bool MLog::UnLockUpdate(const char *msg)
447{
448#ifdef _REENTRANT
449 if (fMuxGui->UnLock()==13)
450 {
451 Info("UnLockUpdate", "%s - tried to unlock mutex locked by other thread\n", msg);
452 return false;
453 }
454#endif
455 return true;
456}
457
458bool MLog::Lock(const char *msg)
459{
460#ifdef _REENTRANT
461 if (fMuxStream->Lock()==13)
462 {
463 Error("Lock", "%s - mutex is already locked by this thread\n", msg);
464 return false;
465 }
466// while (fMuxStream->Lock()==13)
467// usleep(1);
468// {
469// Error("Lock", "%s - mutex is already locked by this thread\n", msg);
470// return false;
471// }
472#endif
473 return true;
474}
475
476bool MLog::UnLock(const char *msg)
477{
478#ifdef _REENTRANT
479 if (fMuxStream->UnLock()==13)
480 {
481 Error("UnLock", "%s - tried to unlock mutex locked by other thread\n", msg);
482 return false;
483 }
484#endif
485 return true;
486}
487
488// --------------------------------------------------------------------------
489//
490// This is called to flush the buffer of the streaming devices
491//
492int MLog::sync()
493{
494 if (!LockUpdate("sync"))
495 usleep(1);
496 WriteBuffer();
497 UnLockUpdate("sync");
498
499 if (fDevice&eStdout)
500 {
501 if (!fIsNull && !TestBit(eNoColors))
502 cout << kReset;
503 cout.flush();
504 }
505
506 if (fDevice&eStderr)
507 cerr.flush();
508
509 if (fDevice&eFile && fOut)
510 fOut->flush();
511
512 return 0;
513}
514
515// --------------------------------------------------------------------------
516//
517// This function comes from streambuf and should
518// output the buffer to the device (flush, endl)
519// or handle a buffer overflow (too many chars)
520// If a real overflow happens i contains the next
521// chars which doesn't fit into the buffer anymore.
522// If the buffer is not really filled i is EOF(-1).
523//
524int MLog::overflow(int i) // i=EOF means not a real overflow
525{
526 //
527 // no output if
528 //
529 if (fOutputLevel <= fDebugLevel)
530 {
531 if (!LockUpdate("overflow"))
532 usleep(1);
533
534 *fPPtr++ = (char)i;
535
536 if (fPPtr == fEPtr)
537 WriteBuffer();
538
539 UnLockUpdate("overflow");
540 }
541
542 return 0;
543}
544
545// --------------------------------------------------------------------------
546//
547// Print usage information setup in Setup()
548//
549void MLog::Usage()
550{
551 // 1 2 3 4 5 6 7 8
552 // 12345678901234567890123456789012345678901234567890123456789012345678901234567890
553 *this << " -v# Verbosity level # [default=2]" << endl;
554 *this << " -a, --no-colors Do not use Ansii color codes" << endl;
555 *this << " --log[=file] Write log-out to ascii-file [default: prgname.log]" << endl;
556 *this << " --html[=file] Write log-out to html-file [default: prgname.html]" << endl;
557 *this << " --debug[=n] Enable root debugging [default: gDebug=1]" << endl;
558 *this << " --null Null output (supresses all output)" << endl;
559}
560
561// --------------------------------------------------------------------------
562//
563// Setup MLog and global debug output from command line arguments.
564//
565void MLog::Setup(MArgs &arg)
566{
567 // FXIME: This is not really at a place where it belongs to!
568 gDebug = arg.HasOption("--debug=") ? arg.GetIntAndRemove("--debug=") : 0;
569 if (gDebug==0 && arg.HasOnlyAndRemove("--debug"))
570 gDebug=1;
571
572 TString f1 = arg.GetStringAndRemove("--log=", "");
573 if (f1.IsNull() && arg.HasOnlyAndRemove("--log"))
574 f1 = Form("%s.log", arg.GetName());
575 if (!f1.IsNull())
576 {
577 SetOutputFile(f1);
578 EnableOutputDevice(eFile);
579 }
580
581 TString f2 = arg.GetStringAndRemove("--html=", "");
582 if (f2.IsNull() && arg.HasOnlyAndRemove("--html"))
583 f2 = Form("%s.html", arg.GetName());
584 if (!f2.IsNull())
585 {
586 MLogHtml *html = new MLogHtml(f2);
587 html->SetBit(kCanDelete);
588 AddPlugin(html);
589 }
590
591 const Bool_t null = arg.HasOnlyAndRemove("--null");
592 if (null)
593 SetNullOutput();
594
595 if (arg.HasOnlyAndRemove("--no-colors") || arg.HasOnlyAndRemove("-a"))
596 SetNoColors();
597
598 SetDebugLevel(arg.GetIntAndRemove("-v", 2));
599}
600
601// --------------------------------------------------------------------------
602//
603// Read the setup from a TEnv:
604// MLog.VerbosityLevel: 0, 1, 2, 3, 4
605// MLog.DebugLevel: 0, 1, 2, 3, 4
606// MLog.NoColors
607//
608// Depending on your setup it might be correct to use something like:
609// Job1.MLog.VerbosityLevel: 1
610// Job1.DebugLevel: 2
611// Job1.MLog.NoColors
612//
613void MLog::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
614{
615 MParContainer mlog("MLog");
616
617 if (mlog.IsEnvDefined(env, prefix+"MLog", "VerbosityLevel", print))
618 SetDebugLevel(mlog.GetEnvValue(env, prefix+"MLog", "VerbosityLevel", 2));
619 else
620 if (mlog.IsEnvDefined(env, "MLog", "VerbosityLevel", print))
621 SetDebugLevel(mlog.GetEnvValue(env, "MLog", "VerbosityLevel", 2));
622
623 if (mlog.IsEnvDefined(env, prefix+"MLog", "DebugLevel", print))
624 gDebug = mlog.GetEnvValue(env, prefix+"MLog", "DebugLevel", 0);
625 else
626 if (mlog.IsEnvDefined(env, "MLog", "DebugLevel", print))
627 gDebug = mlog.GetEnvValue(env, "MLog", "DebugLevel", 0);
628
629 if (mlog.IsEnvDefined(env, prefix+"MLog", "NoColors", print))
630 SetNoColors(mlog.GetEnvValue(env, prefix+"MLog", "NoColors", kFALSE));
631 else
632 if (mlog.IsEnvDefined(env, "MLog", "NoColors", print))
633 SetNoColors(mlog.GetEnvValue(env, "MLog", "NoColors", kFALSE));
634}
635
636// --------------------------------------------------------------------------
637//
638// Read the setup from a TEnv:
639// MLog.VerbosityLevel: 0, 1, 2, 3, 4
640// MLog.DebugLevel: 0, 1, 2, 3, 4
641// MLog.NoColors
642//
643// Depending on your setup it might be correct to use something like:
644// Job1.MLog.VerbosityLevel: 1
645// Job1.DebugLevel: 2
646// Job1.MLog.NoColors
647//
648void MLog::WriteEnv(TEnv &, TString prefix, Bool_t) const
649{
650 if (!prefix.IsNull())
651 prefix += ".";
652 prefix += "MLog";
653
654 cout << "MLog::WriteEnv: not yet implemented!" << endl;
655}
656
657// --------------------------------------------------------------------------
658//
659// Create a new instance of an file output stream
660// an set the corresponding flag
661//
662void MLog::AllocateFile(const char *fname)
663{
664 // gcc 3.2:
665 const char *txt = "logXXXXXX";
666
667 TString n(fname ? fname : txt);
668 gSystem->ExpandPathName(n);
669
670 fOut = new ofstream(n.Data());
671
672 // switch off buffering
673 fOut->rdbuf()->pubsetbuf(0,0);
674
675 fOutAllocated = kTRUE;
676}
677
678// --------------------------------------------------------------------------
679//
680// if fout was allocated by this instance of MLooging
681// delete it.
682//
683void MLog::DeallocateFile()
684{
685 if (fOutAllocated)
686 delete fOut;
687}
688
689// --------------------------------------------------------------------------
690//
691// if necessary delete the old in stance of the file
692// output stream and create a new one
693//
694void MLog::ReallocateFile(const char *fname)
695{
696 DeallocateFile();
697 AllocateFile(fname);
698}
699
700// --------------------------------------------------------------------------
701//
702// This function checks if a device should get enabled or disabled.
703//
704void MLog::CheckFlag(Flags_t chk, int flag)
705{
706 if (flag==-1)
707 return;
708
709 flag ? EnableOutputDevice(chk) : DisableOutputDevice(chk);
710}
711
712// --------------------------------------------------------------------------
713//
714// Add a plugin to which the output should be redirected, eg. MLogHtml
715// The user has to take care of its deletion. If the plugin is deleted
716// (and the kMustCleanup bit was not reset accidentaly) the plugin
717// is automatically removed from the list of active plugins.
718//
719// If MLog should take the ownership call plug->SetBit(kCanDelete);
720//
721void MLog::AddPlugin(MLogPlugin *plug)
722{
723 fPlugins->Add(plug);
724
725 // Make sure that it is recursively deleted from all objects in ListOfCleanups
726 plug->SetBit(kMustCleanup);
727}
728
729// --------------------------------------------------------------------------
730//
731// Returns "yyyy-mm-dd user@host gROOT->GetName()[pid]"
732//
733TString MLog::Intro()
734{
735 UserGroup_t *user = gSystem->GetUserInfo();
736
737 TString rc;
738 rc += MTime(-1).GetSqlDateTime();
739 rc += " ";
740 rc += user->fUser;
741 rc += "@";
742 rc += gSystem->HostName();
743 rc += " ";
744 rc += gROOT->GetName();
745 rc += "[";
746 rc += gSystem->GetPid();
747 rc += "] ";
748
749 delete user;
750
751 return rc;
752}
753
754// --------------------------------------------------------------------------
755//
756// Check whether errors at this level should be ignored.
757//
758bool MLog::ErrorHandlerIgnore(Int_t level)
759{
760 // The default error handler function. It prints the message on stderr and
761 // if abort is set it aborts the application.
762 if (gErrorIgnoreLevel == kUnset) {
763 R__LOCKGUARD2(gErrorMutex);
764
765 gErrorIgnoreLevel = 0;
766 if (gEnv) {
767 TString lvl = gEnv->GetValue("Root.ErrorIgnoreLevel", "Info");
768 if (!lvl.CompareTo("Info",TString::kIgnoreCase))
769 gErrorIgnoreLevel = kInfo;
770 else if (!lvl.CompareTo("Warning",TString::kIgnoreCase))
771 gErrorIgnoreLevel = kWarning;
772 else if (!lvl.CompareTo("Error",TString::kIgnoreCase))
773 gErrorIgnoreLevel = kError;
774 else if (!lvl.CompareTo("Break",TString::kIgnoreCase))
775 gErrorIgnoreLevel = kBreak;
776 else if (!lvl.CompareTo("SysError",TString::kIgnoreCase))
777 gErrorIgnoreLevel = kSysError;
778 else if (!lvl.CompareTo("Fatal",TString::kIgnoreCase))
779 gErrorIgnoreLevel = kFatal;
780 }
781 }
782
783 return level < gErrorIgnoreLevel;
784}
785
786// --------------------------------------------------------------------------
787//
788// Output the root error message to the log-stream.
789//
790void MLog::ErrorHandlerPrint(Int_t level, const char *location, const char *msg)
791{
792 R__LOCKGUARD2(gErrorMutex);
793
794 if (level >= kError)
795 gLog << "ROOT:Error";
796 else
797 if (level >= kSysError)
798 gLog << "SysError";
799 else
800 if (level >= kBreak)
801 gLog << "\n *** Break ***";
802 else
803 if (level >= kFatal)
804 gLog << "Fatal";
805 else
806 if (level >= kWarning)
807 gLog << "ROOT:Warning";
808 else
809 if (level >= kInfo)
810 gLog << "ROOT:Info";
811
812 if (level >= kBreak && level < kSysError)
813 gLog << ": " << msg << std::endl;
814 else
815 if (!location || strlen(location) == 0)
816 gLog << ": " << msg << std::endl;
817 else
818 gLog << " in <" << location << ">: " << msg << std::endl;
819}
820
821// --------------------------------------------------------------------------
822//
823// A new error handler using gLog instead of stderr as output.
824// It is mainly a copy of root's DefaultErrorHandler
825// (see TError.h and TError.cxx)
826//
827void MLog::ErrorHandlerCol(Int_t level, Bool_t abort, const char *location, const char *msg)
828{
829 if (ErrorHandlerIgnore(level))
830 return;
831
832 gLog << std::flush;
833
834 const Int_t store = gLog.GetOutputLevel();
835
836 if (level >= kInfo)
837 gLog << inf;
838 if (level >= kWarning)
839 gLog << warn;
840 if (level >= kError)
841 gLog << err;
842
843 ErrorHandlerPrint(level, location, msg);
844
845 gLog << std::flush;
846
847 gLog.SetOutputLevel(store);
848 if (!abort)
849 return;
850
851 gLog << err << "aborting" << std::endl;
852 if (gSystem) {
853 gSystem->StackTrace();
854 gLog.SetOutputLevel(store);
855 gSystem->Abort();
856 }
857 else
858 {
859 gLog.SetOutputLevel(store);
860 ::abort();
861 }
862}
863
864// --------------------------------------------------------------------------
865//
866// A new error handler using gLog instead of stderr as output.
867// It is mainly a copy of root's DefaultErrorHandler
868// (see TError.h and TError.cxx)
869//
870void MLog::ErrorHandlerAll(Int_t level, Bool_t abort, const char *location, const char *msg)
871{
872 if (ErrorHandlerIgnore(level))
873 return;
874
875 gLog << std::flush << all;
876
877 ErrorHandlerPrint(level, location, msg);
878
879 gLog << std::flush;
880 if (!abort)
881 return;
882
883 gLog << err << "aborting" << std::endl;
884 if (gSystem) {
885 gSystem->StackTrace();
886 gSystem->Abort();
887 } else
888 ::abort();
889}
890
891// --------------------------------------------------------------------------
892//
893// Redirect the root ErrorHandler (see TError.h) output to gLog.
894//
895// The diffrent types are:
896// kColor: Use gLog colors
897// kBlackWhite: Use all-qualifier (as in gLog << all << endl;)
898// kDefault: Set back to root's default error handler
899// (redirect output to stderr)
900//
901void MLog::RedirectErrorHandler(ELogType typ)
902{
903 switch (typ)
904 {
905 case kColor:
906 SetErrorHandler(MLog::ErrorHandlerCol);
907 break;
908 case kBlackWhite:
909 SetErrorHandler(MLog::ErrorHandlerAll);
910 break;
911 case kDefault:
912 SetErrorHandler(DefaultErrorHandler);
913 }
914}
Note: See TracBrowser for help on using the repository browser.