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

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