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

Last change on this file since 2057 was 2054, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 13.2 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 <TGListBox.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), fGuiLineId(0), 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), fGuiLineId(0), 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// TGListBox as the default output device
154//
155MLog::MLog(TGListBox &out) : ostream(this), fPPtr(fBase), fEPtr(fBase+bsz), fOutputLevel(0), fDebugLevel((unsigned)-1), fDevice(eGui), fGuiLineId(0), 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), fGuiLineId(0), 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::Output(ostream &out, int len)
198{
199 if (!TestBit(eNoColors))
200 switch (fOutputLevel)
201 {
202 case 0: out << MLog::kReset; break; // all
203 case 1: out << MLog::kRed; break; // err
204 case 2: out << MLog::kYellow; break; // warn
205 case 3: out << MLog::kGreen; break; // inf
206 }
207
208 // Check for EOL
209 const Bool_t endline = fBase[len-1]=='\n';
210 // output text to screen (without trailing '\0' or '\n')
211 out << TString(fBase, len-1);
212 // reset colors if working with colors
213 if (!TestBit(eNoColors))
214 out << kReset;
215 // output EOL of check found EOL
216 if (endline)
217 out << '\n';
218 out.flush();
219}
220
221// --------------------------------------------------------------------------
222//
223// This is the function which writes the stream physically to a device.
224// If you want to add a new device this must be done here.
225//
226void MLog::WriteBuffer()
227{
228 //
229 // restart writing to the buffer at its first char
230 //
231 const int len = fPPtr - fBase;
232
233 fPPtr = fBase;
234
235 if (fIsNull)
236 return;
237
238 if (fDevice&eStdout)
239 Output(cout, len);
240
241 if (fDevice&eStderr)
242 Output(cerr, len);
243
244 if (fDevice&eFile && fout)
245 fout->write(fBase, len);
246
247 if (fDevice&eGui && fgui)
248 {
249 // check whether the current text was flushed or endl'ed
250 const Bool_t flushed = fBase[len-1]!='\n';
251
252 // for the gui remove trailing characters ('\n' or '\0')
253 fBase[len-1]='\0';
254
255 // add new text to line storage
256 fGuiLine += fBase;
257
258 if (!flushed)
259 {
260 // add a new TString* to the array of gui lines
261 TString **newstr = new TString*[fNumLines+1];
262 memcpy(newstr, fGuiLines, fNumLines*sizeof(TString*));
263 if (fNumLines>0)
264 delete fGuiLines;
265 fGuiLines = newstr;
266
267 // add Gui line as last line of array
268 fGuiLines[fNumLines++] = new TString(fGuiLine);
269 fGuiLine = "";
270 }
271 }
272}
273
274void MLog::UpdateGui()
275{
276 if (fNumLines==0)
277 return;
278
279 // lock mutex
280 Lock();
281
282 // copy lines to TGListBox
283 for (int i=0; i<fNumLines; i++)
284 {
285 // Replace all tabs by 7 white spaces
286 fGuiLines[i]->ReplaceAll("\t", " ");
287 fgui->AddEntry(*fGuiLines[i], fGuiLineId++);
288 delete fGuiLines[i];
289 }
290 delete fGuiLines;
291
292 fNumLines=0;
293
294 // cut list box top 1000 lines
295 fgui->RemoveEntries(0, fGuiLineId-1000);
296 // show last entry
297 fgui->SetTopEntry(fGuiLineId-1);
298 // tell a main loop, that list box contents have changed
299 fgui->SetBit(kHasChanged);
300
301 // release mutex
302 UnLock();
303}
304
305void MLog::Lock()
306{
307#ifdef _REENTRANT
308 pthread_mutex_lock((pthread_mutex_t*)fMuxGui);
309#endif
310}
311
312void MLog::UnLock()
313{
314#ifdef _REENTRANT
315 pthread_mutex_unlock((pthread_mutex_t*)fMuxGui);
316#endif
317}
318
319// --------------------------------------------------------------------------
320//
321// This is called to flush the buffer of the streaming devices
322//
323int MLog::sync()
324{
325 Lock();
326 WriteBuffer();
327 UnLock();
328
329 if (fDevice&eStdout)
330 {
331 cout << kReset;
332 cout.flush();
333 }
334
335 if (fDevice&eStderr)
336 cerr.flush();
337
338 if (fDevice&eFile && fout)
339 fout->flush();
340
341 return 0;
342}
343
344// --------------------------------------------------------------------------
345//
346// This function comes from streambuf and should
347// output the buffer to the device (flush, endl)
348// or handle a buffer overflow (too many chars)
349// If a real overflow happens i contains the next
350// chars which doesn't fit into the buffer anymore.
351// If the buffer is not really filled i is EOF(-1).
352//
353int MLog::overflow(int i) // i=EOF means not a real overflow
354{
355 //
356 // no output if
357 //
358 if (fOutputLevel <= fDebugLevel)
359 {
360 Lock();
361
362 *fPPtr++ = (char)i;
363
364 if (fPPtr == fEPtr)
365 WriteBuffer();
366
367 UnLock();
368 }
369
370 return 0;
371}
372
373// --------------------------------------------------------------------------
374//
375// Create a new instance of an file output stream
376// an set the corresponding flag
377//
378void MLog::AllocateFile(const char *fname)
379{
380 char *txt = (char*)"logXXXXXX";
381 fout = fname ? new ofstream(fname) : new ofstream(mkstemp(txt));
382 fOutAllocated = kTRUE;
383}
384
385// --------------------------------------------------------------------------
386//
387// if fout was allocated by this instance of MLooging
388// delete it.
389//
390void MLog::DeallocateFile()
391{
392 if (fOutAllocated)
393 delete fout;
394}
395
396// --------------------------------------------------------------------------
397//
398// if necessary delete the old in stance of the file
399// output stream and create a new one
400//
401void MLog::ReallocateFile(const char *fname)
402{
403 DeallocateFile();
404 AllocateFile(fname);
405}
406
407// --------------------------------------------------------------------------
408//
409// This function checks if a device should get enabled or disabled.
410//
411void MLog::CheckFlag(Flags_t chk, int flag)
412{
413 if (flag==-1)
414 return;
415
416 flag ? EnableOutputDevice(chk) : DisableOutputDevice(chk);
417}
Note: See TracBrowser for help on using the repository browser.