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

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