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

Last change on this file since 19273 was 14079, checked in by tbretz, 7 years ago
Fit errors are only warings.
File size: 26.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-2006
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MLog
28//
29// This is what we call the logging-system.
30//
31// It is derived from the C++ streaming classes and can handle our
32// logging. The log output can be redirected to stdout, stderr, any other
33// stream or a root window.
34//
35// There is a global log-instance which you can use like cout, id is gLog.
36// A log-instance of your choice (gLog by default) is destributed to all
37// Task which are used in an eventloop, so that you can redirect the output
38// of one eventloop to where you want..
39//
40// The MLog stream has the advantage, that it can be used like the common
41// C++ streams (for example cout). It can redirect the stream to different
42// outputs (console, file, GUI) if necessary at the same time.
43//
44// It supports different debug levels. The debug level of the current
45// stream contents is set by SetDebugLevel, the output level of the
46// current stream can be set by SetOutputLevel.
47//
48// The header file MLogManip.h contains so called manipulators (like flush
49// or setw from iomanip.h) which can manipulate these levels from within
50// stream, for example:
51//    gLog << debug(3) << "Hallo World " << endl;
52// sets the debug level of the following stream to 3
53//
54// edev(), ddev() can be used to enable/disable an output device from
55// within the stream. The enumerations are defined in MLog::_flags
56//
57// Commonly used abbreviations are also defined:
58//    dbginf  Prints source file name and line number. Used for output
59//            which people may like to look up in the code
60//    all     Is streamed to the output in any case. Used for outputs
61//            which are requested by the user (eg TObject::Print)
62//    err     Should be used for fatal errors which stops the current
63//            processing, eg:
64//              gLog << err << "ERROR: TObject::Copy - Stopped" << endl;
65//    warn    Warning means an error occured, but it is not clear whether
66//            this results further procesing or not.
67//    inf     Informs the user about what's going on. Mostly usefull for
68//            debugging, but in general not necessary at all.
69//    dbg     Use this for your private purpose to mark something as debug
70//            output. This is _not_ ment to be persistent!
71//
72// If your console is capable of ANSI colors the stream is displayed
73// in several colors:
74//    all:    default
75//    err:    red
76//    warn:   yellow/brown
77//    inf:    green
78//    dbg:    blue (and all other levels)
79//
80// If you have a dark background on your console you might want to set
81// an environment variable, eg:
82//    export MARSDEFINES=-DHAVE_DARKBACKGROUND
83// and recompile MLog.
84//
85// If your console can display it also 'underline' can be used. This
86// underlines a text till the next 'endl', eg:
87//    gLog << underline << "This is important!" << endl;
88//
89// To switch off ANSI support call: SetNoColors()
90//
91// gLog is a global stream defined like cout or cerr
92//
93//////////////////////////////////////////////////////////////////////////////
94#include "MLog.h"
95
96#include <stdlib.h>     // mkstemp
97
98#include <fstream>
99#include <iomanip>
100
101#include <TROOT.h>      // gROOT->GetListOfCleanups()
102#include <TSystem.h>
103
104#ifdef _REENTRANT
105#include <TMutex.h>
106#endif
107#include <TGTextView.h>
108
109#include <TEnv.h>       // gEnv (ErrorHandler)
110#include <TError.h>     // TError (SetErrorHandler)
111
112#include "MArgs.h"
113#include "MTime.h"
114#include "MString.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:                                  // inf
294        case 4:                                  // inf2
295        case 5:  sout << MLog::kGreen;   break;  // inf3
296        default: sout << MLog::kBlue;    break;  // all others (dbg)
297        }
298
299    if (len>0)
300    {
301        // Check for EOL
302        const Int_t endline = fBase[len-1]=='\n' ? 1 : 0;
303        // output text to screen (without trailing '\n')
304        sout << TString(fBase, len-endline);
305        // reset colors if working with colors
306        if (!TestBit(eNoColors))
307            sout << kReset;
308        // output EOL of check found EOL
309        if (endline)
310        {
311            sout << '\n';
312            // Check whether text was underlined
313            if (TestBit(kIsUnderlined) && TestBit(eNoColors))
314            {
315                sout << setw(len-1) << setfill('-') << "" << "\n";
316                ResetBit(kIsUnderlined);
317            }
318        }
319    }
320    sout.flush();
321}
322
323void MLog::AddGuiLine(const TString &line)
324{
325    // add a new TString* to the array of gui lines
326    TString **newstr = new TString*[fNumLines+1];
327    memcpy(newstr, fGuiLines, fNumLines*sizeof(TString*));
328    if (fNumLines>0)
329        delete [] fGuiLines;
330    fGuiLines = newstr;
331
332    // add Gui line as last line of array
333    fGuiLines[fNumLines++] = new TString(line);
334}
335
336// --------------------------------------------------------------------------
337//
338// This is the function which writes the stream physically to a device.
339// If you want to add a new device this must be done here.
340//
341void MLog::WriteBuffer()
342{
343    //
344    // restart writing to the buffer at its first char
345    //
346    const int len = fPPtr - fBase;
347
348    fPPtr = fBase;
349
350    if (fIsNull)
351        return;
352
353    if (fDevice&eStdout)
354        Output(cout, len);
355
356    if (fDevice&eStderr)
357        Output(cerr, len);
358
359    if (fDevice&eFile && fOut)
360        fOut->write(fBase, len);
361
362    fPlugins->R__FOR_EACH(MLogPlugin, SetColor)(fOutputLevel);
363    fPlugins->R__FOR_EACH(MLogPlugin, WriteBuffer)(fBase, len);
364
365    if (fDevice&eGui && fGui)
366    {
367        // check whether the current text was flushed or endl'ed
368        const Int_t endline = fBase[len-1]=='\n' ? 1 : 0;
369
370        // for the gui remove trailing characters ('\n' or '\0')
371        fBase[len-endline]='\0';
372
373        // add new text to line storage
374        fGuiLine += fBase;
375
376        if (endline)
377        {
378            AddGuiLine(fGuiLine);
379            fGuiLine = "";
380
381            // Check whether text should be underlined
382            if (endline && TestBit(kIsUnderlined))
383            {
384                AddGuiLine("");
385                fGuiLines[fNumLines-1]->Append('-', fGuiLines[fNumLines-2]->Length());
386                ResetBit(kIsUnderlined);
387            }
388        }
389    }
390}
391
392void MLog::UpdateGui()
393{
394    if (fNumLines==0)
395        return;
396
397    // lock mutex
398    if (!LockUpdate("UpdateGui"))
399    {
400        Warning("UpdateGui", "Execution skipped");
401        return;
402    }
403
404    TGText &txt=*fGui->GetText();
405
406    // copy lines to TGListBox
407    for (int i=0; i<fNumLines; i++)
408    {
409        // Replace all tabs by 7 white spaces
410        fGuiLines[i]->ReplaceAll("\t", "       ");
411        txt.InsText(TGLongPosition(0, txt.RowCount()), *fGuiLines[i]);
412        delete fGuiLines[i];
413    }
414    delete [] fGuiLines;
415
416    fNumLines=0;
417
418    // cut text box top 1000 lines
419    //    while (txt.RowCount()>1000)
420    //        txt.DelLine(1);
421
422    // show last entry
423    fGui->Layout();
424    fGui->SetVsbPosition(txt.RowCount()-1);
425
426    // tell a main loop, that list box contents have changed
427    fGui->SetBit(kHasChanged);
428
429    // release mutex
430    UnLockUpdate("UpdateGui");
431}
432
433bool MLog::LockUpdate(const char *msg)
434{
435#ifdef _REENTRANT
436    if (fMuxGui->Lock()==13)
437    {
438        Info("LockUpdate", "%s - mutex is already locked by this thread\n", msg);
439        return false;
440    }
441#endif
442    return true;
443}
444
445bool MLog::UnLockUpdate(const char *msg)
446{
447#ifdef _REENTRANT
448    if (fMuxGui->UnLock()==13)
449    {
450        Info("UnLockUpdate", "%s - tried to unlock mutex locked by other thread\n", msg);
451        return false;
452    }
453#endif
454    return true;
455}
456
457bool MLog::Lock(const char *msg)
458{
459#ifdef _REENTRANT
460    if (fMuxStream->Lock()==13)
461    {
462        Error("Lock", "%s - mutex is already locked by this thread\n", msg);
463        return false;
464    }
465//    while (fMuxStream->Lock()==13)
466//        usleep(1);
467//    {
468//        Error("Lock", "%s - mutex is already locked by this thread\n", msg);
469//        return false;
470//    }
471#endif
472    return true;
473}
474
475bool MLog::UnLock(const char *msg)
476{
477#ifdef _REENTRANT
478    if (fMuxStream->UnLock()==13)
479    {
480        Error("UnLock", "%s - tried to unlock mutex locked by other thread\n", msg);
481        return false;
482    }
483#endif
484    return true;
485}
486
487// --------------------------------------------------------------------------
488//
489// This is called to flush the buffer of the streaming devices
490//
491int MLog::sync()
492{
493    if (!LockUpdate("sync"))
494        usleep(1);
495    WriteBuffer();
496    UnLockUpdate("sync");
497
498    if (fDevice&eStdout)
499    {
500        if (!fIsNull && !TestBit(eNoColors))
501            cout << kReset;
502        cout.flush();
503    }
504
505    if (fDevice&eStderr)
506        cerr.flush();
507
508    if (fDevice&eFile && fOut)
509        fOut->flush();
510
511    return 0;
512}
513
514// --------------------------------------------------------------------------
515//
516// This function comes from streambuf and should
517// output the buffer to the device (flush, endl)
518// or handle a buffer overflow (too many chars)
519// If a real overflow happens i contains the next
520// chars which doesn't fit into the buffer anymore.
521// If the buffer is not really filled i is EOF(-1).
522//
523int MLog::overflow(int i) // i=EOF means not a real overflow
524{
525    //
526    // no output if
527    //
528    if (fOutputLevel <= fDebugLevel)
529    {
530        if (!LockUpdate("overflow"))
531            usleep(1);
532
533        *fPPtr++ = (char)i;
534
535        if (fPPtr == fEPtr)
536            WriteBuffer();
537
538        UnLockUpdate("overflow");
539    }
540
541    return 0;
542}
543
544// --------------------------------------------------------------------------
545//
546// Print usage information setup in Setup()
547//
548void MLog::Usage()
549{
550    //                 1         2         3         4         5         6         7         8
551    //        12345678901234567890123456789012345678901234567890123456789012345678901234567890
552    *this << "   -v#                       Verbosity level # [default=2]" << endl;
553    *this << "   -a, --no-colors           Do not use Ansii color codes" << endl;
554    *this << "   --log[=file]              Write log-out to ascii-file [default: prgname.log]" << endl;
555    *this << "   --html[=file]             Write log-out to html-file [default: prgname.html]" << endl;
556    *this << "   --debug[=n]               Enable root debugging [default: gDebug=1]" << endl;
557    *this << "   --null                    Null output (supresses all output)" << endl;
558}
559
560// --------------------------------------------------------------------------
561//
562// Setup MLog and global debug output from command line arguments.
563//
564void MLog::Setup(MArgs &arg)
565{
566    // FXIME: This is not really at a place where it belongs to!
567    gDebug = arg.HasOption("--debug=") ? arg.GetIntAndRemove("--debug=") : 0;
568    if (gDebug==0 && arg.HasOnlyAndRemove("--debug"))
569        gDebug=1;
570
571    TString f1 = arg.GetStringAndRemove("--log=", "");
572    if (f1.IsNull() && arg.HasOnlyAndRemove("--log"))
573        f1 = MString::Format("%s.log", arg.GetName());
574    if (!f1.IsNull())
575    {
576        SetOutputFile(f1);
577        EnableOutputDevice(eFile);
578    }
579
580    TString f2 = arg.GetStringAndRemove("--html=", "");
581    if (f2.IsNull() && arg.HasOnlyAndRemove("--html"))
582        f2 = MString::Format("%s.html", arg.GetName());
583    if (!f2.IsNull())
584    {
585        MLogHtml *html = new MLogHtml(f2);
586        html->SetBit(kCanDelete);
587        AddPlugin(html);
588    }
589
590    const Bool_t null = arg.HasOnlyAndRemove("--null");
591    if (null)
592        SetNullOutput();
593
594    if (arg.HasOnlyAndRemove("--no-colors") || arg.HasOnlyAndRemove("-a"))
595        SetNoColors();
596
597    SetDebugLevel(arg.GetIntAndRemove("-v", 2));
598}
599
600// --------------------------------------------------------------------------
601//
602// Read the setup from a TEnv:
603//   MLog.VerbosityLevel: 0, 1, 2, 3, 4
604//   MLog.DebugLevel: 0, 1, 2, 3, 4
605//   MLog.NoColors
606//
607// Depending on your setup it might be correct to use something like:
608//   Job1.MLog.VerbosityLevel: 1
609//   Job1.DebugLevel: 2
610//   Job1.MLog.NoColors
611//
612void MLog::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
613{
614    MParContainer mlog("MLog");
615
616    if (mlog.IsEnvDefined(env, prefix+"MLog", "VerbosityLevel", print))
617        SetDebugLevel(mlog.GetEnvValue(env, prefix+"MLog", "VerbosityLevel", 2));
618    else
619        if (mlog.IsEnvDefined(env, "MLog", "VerbosityLevel", print))
620            SetDebugLevel(mlog.GetEnvValue(env, "MLog", "VerbosityLevel", 2));
621
622    if (mlog.IsEnvDefined(env, prefix+"MLog", "DebugLevel", print))
623        gDebug = mlog.GetEnvValue(env, prefix+"MLog", "DebugLevel", 0);
624    else
625        if (mlog.IsEnvDefined(env, "MLog", "DebugLevel", print))
626            gDebug = mlog.GetEnvValue(env, "MLog", "DebugLevel", 0);
627
628    if (mlog.IsEnvDefined(env, prefix+"MLog", "NoColors", print))
629        SetNoColors(mlog.GetEnvValue(env, prefix+"MLog", "NoColors", kFALSE));
630    else
631        if (mlog.IsEnvDefined(env, "MLog", "NoColors", print))
632            SetNoColors(mlog.GetEnvValue(env, "MLog", "NoColors", kFALSE));
633}
634
635// --------------------------------------------------------------------------
636//
637// Read the setup from a TEnv:
638//   MLog.VerbosityLevel: 0, 1, 2, 3, 4
639//   MLog.DebugLevel: 0, 1, 2, 3, 4
640//   MLog.NoColors
641//
642// Depending on your setup it might be correct to use something like:
643//   Job1.MLog.VerbosityLevel: 1
644//   Job1.DebugLevel: 2
645//   Job1.MLog.NoColors
646//
647void MLog::WriteEnv(TEnv &, TString prefix, Bool_t) const
648{
649    if (!prefix.IsNull())
650        prefix += ".";
651    prefix += "MLog";
652
653    cout << "MLog::WriteEnv: not yet implemented!" << endl;
654}
655
656// --------------------------------------------------------------------------
657//
658// Create a new instance of an file output stream
659// an set the corresponding flag
660//
661void MLog::AllocateFile(const char *fname)
662{
663    // gcc 3.2:
664    const char *txt = "logXXXXXX";
665
666    TString n(fname ? fname : txt);
667    gSystem->ExpandPathName(n);
668
669    fOut = new ofstream(n.Data());
670
671    // switch off buffering
672    fOut->rdbuf()->pubsetbuf(0,0);
673
674    fOutAllocated = kTRUE;
675}
676
677// --------------------------------------------------------------------------
678//
679// if fout was allocated by this instance of MLooging
680// delete it.
681//
682void MLog::DeallocateFile()
683{
684    if (fOutAllocated)
685        delete fOut;
686}
687
688// --------------------------------------------------------------------------
689//
690// if necessary delete the old in stance of the file
691// output stream and create a new one
692//
693void MLog::ReallocateFile(const char *fname)
694{
695    DeallocateFile();
696    AllocateFile(fname);
697}
698
699// --------------------------------------------------------------------------
700//
701// This function checks if a device should get enabled or disabled.
702//
703void MLog::CheckFlag(Flags_t chk, int flag)
704{
705    if (flag==-1)
706        return;
707
708    flag ? EnableOutputDevice(chk) : DisableOutputDevice(chk);
709}
710
711// --------------------------------------------------------------------------
712//
713// Add a plugin to which the output should be redirected, eg. MLogHtml
714// The user has to take care of its deletion. If the plugin is deleted
715// (and the kMustCleanup bit was not reset accidentaly) the plugin
716// is automatically removed from the list of active plugins.
717//
718// If MLog should take the ownership call plug->SetBit(kCanDelete);
719//
720void MLog::AddPlugin(MLogPlugin *plug)
721{
722    fPlugins->Add(plug);
723
724    // Make sure that it is recursively deleted from all objects in ListOfCleanups
725    plug->SetBit(kMustCleanup);
726}
727
728// --------------------------------------------------------------------------
729//
730// Returns "yyyy-mm-dd user@host gROOT->GetName()[pid]"
731//
732TString MLog::Intro()
733{
734    UserGroup_t *user = gSystem->GetUserInfo();
735
736    TString rc;
737    rc += MTime(-1).GetSqlDateTime();
738    rc += " ";
739    rc += user->fUser;
740    rc += "@";
741    rc += gSystem->HostName();
742    rc += " ";
743    rc += gROOT->GetName();
744    rc += "[";
745    rc += gSystem->GetPid();
746    rc += "] ";
747
748    delete user;
749
750    return rc;
751}
752
753// --------------------------------------------------------------------------
754//
755// Check whether errors at this level should be ignored.
756//
757bool MLog::ErrorHandlerIgnore(Int_t level)
758{
759    // The default error handler function. It prints the message on stderr and
760    // if abort is set it aborts the application.
761   if (gErrorIgnoreLevel == kUnset) {
762      R__LOCKGUARD2(gErrorMutex);
763
764      gErrorIgnoreLevel = 0;
765      if (gEnv) {
766         TString lvl = gEnv->GetValue("Root.ErrorIgnoreLevel", "Info");
767         if (!lvl.CompareTo("Info",TString::kIgnoreCase))
768            gErrorIgnoreLevel = kInfo;
769         else if (!lvl.CompareTo("Warning",TString::kIgnoreCase))
770            gErrorIgnoreLevel = kWarning;
771         else if (!lvl.CompareTo("Error",TString::kIgnoreCase))
772            gErrorIgnoreLevel = kError;
773         else if (!lvl.CompareTo("Break",TString::kIgnoreCase))
774            gErrorIgnoreLevel = kBreak;
775         else if (!lvl.CompareTo("SysError",TString::kIgnoreCase))
776            gErrorIgnoreLevel = kSysError;
777         else if (!lvl.CompareTo("Fatal",TString::kIgnoreCase))
778            gErrorIgnoreLevel = kFatal;
779      }
780   }
781
782   return level < gErrorIgnoreLevel;
783}
784
785// --------------------------------------------------------------------------
786//
787// Output the root error message to the log-stream.
788//
789void MLog::ErrorHandlerPrint(Int_t level, const char *location, const char *msg)
790{
791    R__LOCKGUARD2(gErrorMutex);
792
793    if (level >= kError)
794        gLog << "ROOT:Error";
795    else
796        if (level >= kSysError)
797            gLog << "SysError";
798        else
799            if (level >= kBreak)
800                gLog << "\n *** Break ***";
801            else
802                if (level >= kFatal)
803                    gLog << "Fatal";
804                else
805                    if (level >= kWarning)
806                        gLog << "ROOT:Warning";
807                    else
808                        if (level >= kInfo)
809                            gLog << "ROOT:Info";
810
811    if (level >= kBreak && level < kSysError)
812        gLog << ": " << msg << std::endl;
813    else
814        if (location==0 || location[0]==0)
815            gLog << ": " << msg << std::endl;
816        else
817            gLog << " in <" << location << ">: " << msg << std::endl;
818}
819
820// --------------------------------------------------------------------------
821//
822// A new error handler using gLog instead of stderr as output.
823// It is mainly a copy of root's DefaultErrorHandler
824// (see TError.h and TError.cxx)
825//
826void MLog::ErrorHandlerCol(Int_t level, Bool_t abort, const char *location, const char *msg)
827{
828    if (ErrorHandlerIgnore(level))
829        return;
830
831    // This is a really stupid hack/workaround to suppress these
832    // annoying errors in case of a log-scale set too early
833    if (level==kError && !strcmp(location, "THistPainter::PaintInit"))
834        level=kInfo+2;
835
836    // This is a really stupid hack/workaround to suppress these
837    // annoying errors in case of 0 number of points
838    if (level==kError && !strcmp(location, "TGraphPainter::PaintGraph"))
839        level=kInfo+2;
840
841    // This is a really stupid hack/workaround to suppress these
842    // annoying errors in case of 0 number of points
843    if (level==kWarning && !strcmp(location, "Fit"))
844        level=kInfo+2;
845
846    gLog << std::flush;
847
848    const Int_t store = gLog.GetOutputLevel();
849
850    if (level >= kInfo)
851        gLog << inf;
852    if (level==kInfo+1)
853        gLog << inf2;
854    if (level==kInfo+2)
855        gLog << inf3;
856    if (level >= kWarning)
857        gLog << warn;
858    if (level >= kError)
859        gLog << err;
860
861    ErrorHandlerPrint(level, location, msg);
862
863    gLog << std::flush;
864
865    gLog.SetOutputLevel(store);
866    if (!abort)
867        return;
868
869    gLog << err << "aborting" << std::endl;
870    if (gSystem) {
871        gSystem->StackTrace();
872        gLog.SetOutputLevel(store);
873        gSystem->Abort();
874    }
875    else
876    {
877        gLog.SetOutputLevel(store);
878        ::abort();
879    }
880}
881
882// --------------------------------------------------------------------------
883//
884// A new error handler using gLog instead of stderr as output.
885// It is mainly a copy of root's DefaultErrorHandler
886// (see TError.h and TError.cxx)
887//
888void MLog::ErrorHandlerAll(Int_t level, Bool_t abort, const char *location, const char *msg)
889{
890    if (ErrorHandlerIgnore(level))
891        return;
892
893    gLog << std::flush << all;
894
895    ErrorHandlerPrint(level, location, msg);
896
897    gLog << std::flush;
898    if (!abort)
899        return;
900
901    gLog << err << "aborting" << std::endl;
902    if (gSystem) {
903        gSystem->StackTrace();
904        gSystem->Abort();
905    } else
906        ::abort();
907}
908
909// --------------------------------------------------------------------------
910//
911// Redirect the root ErrorHandler (see TError.h) output to gLog.
912//
913// The diffrent types are:
914//  kColor:      Use gLog colors
915//  kBlackWhite: Use all-qualifier (as in gLog << all << endl;)
916//  kDefault:    Set back to root's default error handler
917//               (redirect output to stderr)
918//
919void MLog::RedirectErrorHandler(ELogType typ)
920{
921    switch (typ)
922    {
923    case kColor:
924        SetErrorHandler(MLog::ErrorHandlerCol);
925        break;
926    case kBlackWhite:
927        SetErrorHandler(MLog::ErrorHandlerAll);
928        break;
929    case kDefault:
930        SetErrorHandler(DefaultErrorHandler);
931    }
932}
Note: See TracBrowser for help on using the repository browser.