source: trunk/Mars/mbase/MLog.cc@ 10113

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