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

Last change on this file since 1935 was 1895, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 11.3 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
91//
92// This is the definition of the global log facility
93//
94MLog gLog;
95
96// --------------------------------------------------------------------------
97//
98// this strange usage of an unbufferd buffer is a workaround
99// to make it work on Alpha and Linux!
100//
101void MLog::Init()
102{
103 setp(&fBuffer, &fBuffer+1);
104 *this << '\0';
105
106#ifdef _REENTRANT
107 //
108 // Creat drawing semaphore
109 //
110 fMuxGui = new pthread_mutex_t;
111 pthread_mutex_init((pthread_mutex_t*)fMuxGui, NULL);
112#endif
113}
114
115// --------------------------------------------------------------------------
116//
117// default constructor which initializes the streamer and sets the device
118// which is used for the output (i)
119//
120MLog::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)
121{
122 Init();
123}
124
125// --------------------------------------------------------------------------
126//
127// default constructor which initializes the streamer and sets the given
128// ofstream as the default output device
129//
130MLog::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)
131{
132 Init();
133}
134
135// --------------------------------------------------------------------------
136//
137// default constructor which initializes the streamer and sets the given
138// TGListBox as the default output device
139//
140MLog::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)
141{
142 Init();
143}
144
145// --------------------------------------------------------------------------
146//
147// default constructor which initializes the streamer and opens a file with
148// the given name. Dependend on the flag the file is set as output device
149// or not.
150//
151MLog::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)
152{
153 Init();
154
155 AllocateFile(fname);
156 CheckFlag(eFile, flag);
157}
158
159// --------------------------------------------------------------------------
160//
161// Destructor, destroying the gui mutex.
162//
163MLog::~MLog()
164{
165 DeallocateFile();
166#ifdef _REENTRANT
167 pthread_mutex_destroy((pthread_mutex_t*)fMuxGui);
168#endif
169}
170
171// --------------------------------------------------------------------------
172//
173// copyt constructor
174//
175MLog::MLog(MLog &log)
176{
177 fOutputLevel = log.fOutputLevel;
178 fDebugLevel = log.fDebugLevel;
179 fDevice = log.fDevice;
180}
181
182// --------------------------------------------------------------------------
183//
184// This is the function which writes the stream physically to a device.
185// If you want to add a new device this must be done here.
186//
187void MLog::WriteBuffer()
188{
189 //
190 // restart writing to the buffer at its first char
191 //
192 const int len = fPPtr - fBase;
193
194 fPPtr = fBase;
195
196 if (fIsNull)
197 return;
198
199 if (fDevice&eStdout)
200 cout.write(fBase, len);
201
202 if (fDevice&eStderr)
203 cerr.write(fBase, len);
204
205 if (fDevice&eFile && fout)
206 fout->write(fBase, len);
207
208 if (fDevice&eGui && fgui)
209 {
210 char **newstr = new char*[fNumLines+1];
211
212 for (int i=0; i<fNumLines; i++)
213 newstr[i] = fGuiLines[i];
214
215 if (fNumLines>0)
216 delete fGuiLines;
217
218 char *dummy = new char[len];
219 memcpy(dummy, fBase, len-1);
220 dummy[len-1]='\0';
221
222 newstr[fNumLines++] = dummy;
223
224 fGuiLines = newstr;
225 }
226}
227
228void MLog::UpdateGui()
229{
230 if (fNumLines==0)
231 return;
232
233 Lock();
234
235 for (int i=0; i<fNumLines; i++)
236 {
237 fgui->AddEntry(fGuiLines[i], fGuiLineId++);
238 delete fGuiLines[i];
239 }
240
241 delete fGuiLines;
242
243 fNumLines=0;
244
245 fgui->RemoveEntries(0, fGuiLineId-1000);
246 fgui->SetTopEntry(fGuiLineId-1);
247 fgui->SetBit(kHasChanged);
248
249 UnLock();
250}
251
252void MLog::Lock()
253{
254#ifdef _REENTRANT
255 pthread_mutex_lock((pthread_mutex_t*)fMuxGui);
256#endif
257}
258
259void MLog::UnLock()
260{
261#ifdef _REENTRANT
262 pthread_mutex_unlock((pthread_mutex_t*)fMuxGui);
263#endif
264}
265
266// --------------------------------------------------------------------------
267//
268// This is called to flush the buffer of the streaming devices
269//
270int MLog::sync()
271{
272 Lock();
273 WriteBuffer();
274 UnLock();
275
276 if (fDevice&eStdout)
277 cout.flush();
278
279 if (fDevice&eStderr)
280 cerr.flush();
281
282 if (fDevice&eFile && fout)
283 fout->flush();
284
285 return 0;
286}
287
288// --------------------------------------------------------------------------
289//
290// This function comes from streambuf and should
291// output the buffer to the device (flush, endl)
292// or handle a buffer overflow (too many chars)
293// If a real overflow happens i contains the next
294// chars which doesn't fit into the buffer anymore.
295// If the buffer is not really filled i is EOF(-1).
296//
297int MLog::overflow(int i) // i=EOF means not a real overflow
298{
299 //
300 // no output if
301 //
302 if (fOutputLevel <= fDebugLevel)
303 {
304 Lock();
305
306 *fPPtr++ = (char)i;
307
308 if (fPPtr == fEPtr)
309 WriteBuffer();
310
311 UnLock();
312 }
313
314 return 0;
315}
316
317// --------------------------------------------------------------------------
318//
319// Create a new instance of an file output stream
320// an set the corresponding flag
321//
322void MLog::AllocateFile(const char *fname)
323{
324 char *txt = (char*)"logXXXXXX";
325 fout = fname ? new ofstream(fname) : new ofstream(mkstemp(txt));
326 fOutAllocated = kTRUE;
327}
328
329// --------------------------------------------------------------------------
330//
331// if fout was allocated by this instance of MLooging
332// delete it.
333//
334void MLog::DeallocateFile()
335{
336 if (fOutAllocated)
337 delete fout;
338}
339
340// --------------------------------------------------------------------------
341//
342// if necessary delete the old in stance of the file
343// output stream and create a new one
344//
345void MLog::ReallocateFile(const char *fname)
346{
347 DeallocateFile();
348 AllocateFile(fname);
349}
350
351// --------------------------------------------------------------------------
352//
353// This function checks if a device should get enabled or disabled.
354//
355void MLog::CheckFlag(Flags_t chk, int flag)
356{
357 if (flag==-1)
358 return;
359
360 flag ? EnableOutputDevice(chk) : DisableOutputDevice(chk);
361}
Note: See TracBrowser for help on using the repository browser.