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

Last change on this file since 9627 was 9343, checked in by tbretz, 11 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.