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

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