source: tags/Mars-V0.8.3/mbase/MLog.cc

Last change on this file was 2519, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 13.5 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@uni-sw.gwdg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2001
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#ifdef _REENTRANT
103#include <TMutex.h>
104#endif
105#include <TGTextView.h>
106
107ClassImp(MLog);
108
109using namespace std;
110
111// root 3.02:
112// check for TObjectWarning, TObject::Info, gErrorIgnoreLevel
113
114const char MLog::kESC = '\033'; // (char)27
115const char *const MLog::kEsc = "\033[";
116const char *const MLog::kReset = "\033[0m";
117const char *const MLog::kRed = "\033[31m";
118const char *const MLog::kGreen = "\033[32m";
119#ifdef HAVE_DARKBACKGROUND
120const char *const MLog::kYellow = "\033[33m\033[1m";
121#else
122const char *const MLog::kYellow = "\033[33m";
123#endif
124const char *const MLog::kBlue = "\033[34m";
125const char *const MLog::kUnderline = "\033[4m";;
126const char *const MLog::kBlink = "\033[5m";;
127const char *const MLog::kBright = "\033[1m";;
128const char *const MLog::kDark = "\033[2m";;
129
130//
131// This is the definition of the global log facility
132//
133MLog gLog;
134
135// --------------------------------------------------------------------------
136//
137// this strange usage of an unbufferd buffer is a workaround
138// to make it work on Alpha and Linux!
139//
140void MLog::Init()
141{
142 setp(&fBuffer, &fBuffer+1);
143 *this << '\0';
144
145#ifdef _REENTRANT
146 //
147 // Creat drawing semaphore
148 //
149 fMuxGui = new TMutex;
150#endif
151}
152
153// --------------------------------------------------------------------------
154//
155// default constructor which initializes the streamer and sets the device
156// which is used for the output (i)
157//
158MLog::MLog(int i) : ostream(this), fPPtr(fBase), fEPtr(fBase+bsz), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(i), fIsNull(kFALSE), fOut(NULL), fOutAllocated(kFALSE), fGui(NULL), fNumLines(0)
159{
160 Init();
161}
162
163// --------------------------------------------------------------------------
164//
165// default constructor which initializes the streamer and sets the given
166// ofstream as the default output device
167//
168MLog::MLog(ofstream &out) : ostream(this), fPPtr(fBase), fEPtr(fBase+bsz), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(eFile), fIsNull(kFALSE), fOut(&out), fOutAllocated(kFALSE), fGui(NULL), fNumLines(0)
169{
170 Init();
171}
172
173// --------------------------------------------------------------------------
174//
175// default constructor which initializes the streamer and sets the given
176// TGTextView as the default output device
177//
178MLog::MLog(TGTextView &out) : ostream(this), fPPtr(fBase), fEPtr(fBase+bsz), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(eGui), fOut(NULL), fOutAllocated(kFALSE), fGui(&out), fNumLines(0)
179{
180 Init();
181}
182
183// --------------------------------------------------------------------------
184//
185// default constructor which initializes the streamer and opens a file with
186// the given name. Dependend on the flag the file is set as output device
187// or not.
188//
189MLog::MLog(const char *fname, int flag) : ostream(this), fPPtr(fBase), fEPtr(fBase+bsz), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(eFile), fIsNull(kFALSE), fGui(NULL), fNumLines(0)
190{
191 Init();
192
193 AllocateFile(fname);
194 CheckFlag(eFile, flag);
195}
196
197// --------------------------------------------------------------------------
198//
199// Destructor, destroying the gui mutex.
200//
201MLog::~MLog()
202{
203 DeallocateFile();
204#ifdef _REENTRANT
205 delete fMuxGui;
206#endif
207}
208
209// --------------------------------------------------------------------------
210//
211// copyt constructor
212//
213/*
214MLog::MLog(MLog const& log)
215{
216// fOutputLevel = log.fOutputLevel;
217// fDebugLevel = log.fDebugLevel;
218// fDevice = log.fDevice;
219}
220*/
221
222void MLog::Underline()
223{
224 SetBit(kIsUnderlined);
225
226 if (TestBit(eNoColors))
227 return;
228
229 if (fDevice&eStdout)
230 cout << kUnderline;
231
232 if (fDevice&eStderr)
233 cerr << kUnderline;
234}
235
236void MLog::Output(ostream &out, int len)
237{
238 if (!TestBit(eNoColors))
239 switch (fOutputLevel)
240 {
241 // do not output reset. Otherwise we reset underline in 0-mode
242 // case 1: out << MLog::kReset; break; // all
243 case 0: break; // all = background color
244 case 1: out << MLog::kRed; break; // err
245 case 2: out << MLog::kYellow; break; // warn
246 case 3: out << MLog::kGreen; break; // inf
247 default: out << MLog::kBlue; break; // all others (dbg)
248 }
249
250 if (len>0)
251 {
252 // Check for EOL
253 const Int_t endline = fBase[len-1]=='\n' ? 1 : 0;
254 // output text to screen (without trailing '\n')
255 out << TString(fBase, len-endline);
256 // reset colors if working with colors
257 if (!TestBit(eNoColors))
258 out << kReset;
259 // output EOL of check found EOL
260 if (endline)
261 {
262 out << '\n';
263 // Check whether text was underlined
264 if (TestBit(kIsUnderlined) && TestBit(eNoColors))
265 {
266 out << setw(len-1) << setfill('-') << "" << "\n";
267 ResetBit(kIsUnderlined);
268 }
269 }
270 }
271 out.flush();
272}
273
274void MLog::AddGuiLine(const TString &line)
275{
276 // add a new TString* to the array of gui lines
277 TString **newstr = new TString*[fNumLines+1];
278 memcpy(newstr, fGuiLines, fNumLines*sizeof(TString*));
279 if (fNumLines>0)
280 delete fGuiLines;
281 fGuiLines = newstr;
282
283 // add Gui line as last line of array
284 fGuiLines[fNumLines++] = new TString(line);
285}
286
287// --------------------------------------------------------------------------
288//
289// This is the function which writes the stream physically to a device.
290// If you want to add a new device this must be done here.
291//
292void MLog::WriteBuffer()
293{
294 //
295 // restart writing to the buffer at its first char
296 //
297 const int len = fPPtr - fBase;
298
299 fPPtr = fBase;
300
301 if (fIsNull)
302 return;
303
304 if (fDevice&eStdout)
305 Output(cout, len);
306
307 if (fDevice&eStderr)
308 Output(cerr, len);
309
310 if (fDevice&eFile && fOut)
311 fOut->write(fBase, len);
312
313 if (fDevice&eGui && fGui)
314 {
315 // check whether the current text was flushed or endl'ed
316 const Int_t endline = fBase[len-1]=='\n' ? 1 : 0;
317
318 // for the gui remove trailing characters ('\n' or '\0')
319 fBase[len-endline]='\0';
320
321 // add new text to line storage
322 fGuiLine += fBase;
323
324 if (endline)
325 {
326 AddGuiLine(fGuiLine);
327 fGuiLine = "";
328
329 // Check whether text should be underlined
330 if (endline && TestBit(kIsUnderlined))
331 {
332 AddGuiLine("");
333 fGuiLines[fNumLines-1]->Append('-', fGuiLines[fNumLines-2]->Length());
334 ResetBit(kIsUnderlined);
335 }
336 }
337 }
338}
339
340void MLog::UpdateGui()
341{
342 if (fNumLines==0)
343 return;
344
345 // lock mutex
346 Lock();
347
348 TGText &txt=*fGui->GetText();
349
350 // copy lines to TGListBox
351 for (int i=0; i<fNumLines; i++)
352 {
353 // Replace all tabs by 7 white spaces
354 fGuiLines[i]->ReplaceAll("\t", " ");
355 txt.InsText(TGLongPosition(0, txt.RowCount()), *fGuiLines[i]);
356 delete fGuiLines[i];
357 }
358 delete fGuiLines;
359
360 fNumLines=0;
361
362 // cut text box top 1000 lines
363 // while (txt.RowCount()>1000)
364 // txt.DelLine(1);
365
366 // show last entry
367 fGui->Layout();
368 fGui->SetVsbPosition(txt.RowCount()-1);
369
370 // tell a main loop, that list box contents have changed
371 fGui->SetBit(kHasChanged);
372
373 // release mutex
374 UnLock();
375}
376
377void MLog::Lock()
378{
379#ifdef _REENTRANT
380 fMuxGui->Lock();
381#endif
382}
383
384void MLog::UnLock()
385{
386#ifdef _REENTRANT
387 fMuxGui->UnLock();
388#endif
389}
390
391// --------------------------------------------------------------------------
392//
393// This is called to flush the buffer of the streaming devices
394//
395int MLog::sync()
396{
397 Lock();
398 WriteBuffer();
399 UnLock();
400
401 if (fDevice&eStdout)
402 {
403 if (!TestBit(eNoColors))
404 cout << kReset;
405 cout.flush();
406 }
407
408 if (fDevice&eStderr)
409 cerr.flush();
410
411 if (fDevice&eFile && fOut)
412 fOut->flush();
413
414 return 0;
415}
416
417// --------------------------------------------------------------------------
418//
419// This function comes from streambuf and should
420// output the buffer to the device (flush, endl)
421// or handle a buffer overflow (too many chars)
422// If a real overflow happens i contains the next
423// chars which doesn't fit into the buffer anymore.
424// If the buffer is not really filled i is EOF(-1).
425//
426int MLog::overflow(int i) // i=EOF means not a real overflow
427{
428 //
429 // no output if
430 //
431 if (fOutputLevel <= fDebugLevel)
432 {
433 Lock();
434
435 *fPPtr++ = (char)i;
436
437 if (fPPtr == fEPtr)
438 WriteBuffer();
439
440 UnLock();
441 }
442
443 return 0;
444}
445
446// --------------------------------------------------------------------------
447//
448// Create a new instance of an file output stream
449// an set the corresponding flag
450//
451void MLog::AllocateFile(const char *fname)
452{
453 // gcc 3.2:
454 char *txt = (char*)"logXXXXXX";
455 fOut = fname ? new ofstream(fname) : new ofstream(/*mkstemp(*/txt/*)*/);
456 fOutAllocated = kTRUE;
457}
458
459// --------------------------------------------------------------------------
460//
461// if fout was allocated by this instance of MLooging
462// delete it.
463//
464void MLog::DeallocateFile()
465{
466 if (fOutAllocated)
467 delete fOut;
468}
469
470// --------------------------------------------------------------------------
471//
472// if necessary delete the old in stance of the file
473// output stream and create a new one
474//
475void MLog::ReallocateFile(const char *fname)
476{
477 DeallocateFile();
478 AllocateFile(fname);
479}
480
481// --------------------------------------------------------------------------
482//
483// This function checks if a device should get enabled or disabled.
484//
485void MLog::CheckFlag(Flags_t chk, int flag)
486{
487 if (flag==-1)
488 return;
489
490 flag ? EnableOutputDevice(chk) : DisableOutputDevice(chk);
491}
Note: See TracBrowser for help on using the repository browser.