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

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