Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
#ifndef ERRLOG_HH
#define ERRLOG_HH
//--------------------------------------------------------------------------
// Description:
// Class ErrLogger:
// Interface description for the abstract logging interface
//
// BaBar Usage:
//
// BaBar policy for using ErrLogger is to interact with it only
// through the ErrMsg macro.
//
// ErrMsg(severity) << "the message" << endmsg;
//
// The error message must be terminated by endmsg as above.
//
// The ErrMsg macro returns an ostream& so that it is possible
// to include any constructs that can be sent to cout or cerr.
// For example, the string classes and user-defined operator<<
// are available to users while using ErrMsg.
//
// General Usage:
//
// Available constructs are a logging call:
//
// ErrLog::msg(severity, facility, code) << "Foo" << endmsg;
//
// and a test to see if a particular logging call will do anything:
//
// if (ErrLog::logging(severity, facility, code)) ...
//
// All error messages should be completed with "endmsg". For multiple-
// line messages use '\n' for line breaks in preference to endl. The
// endmsg command will supply a final "endl" for error loggers for which
// it's appropriate (e.g., if writing to the console). Users should in
// particular NOT terminate messages with "some text" << endl << endmsg;.
//
//
// "severity" is a member of an enum; see the definition below
// "facility" names the source of the message; in the ErrMsg() form,
// this is set to be the filename and line number
// "code" an integer distinguishing the individual errors possible;
// no meanings are predefined at this level
//
//
// Environment:
// Software developed for the BaBar Detector at the SLAC B-Factory.
//
// Author List:
// Bob Jacobsen (original author)
// Scott Metzler (addition of ErrStream)
// Gregory Dubois-Felsmann (ErrOpt; conversion of "code" to int)
// $Id: ErrLog.hh,v 1.1.1.1 2005/03/29 17:04:19 steinke Exp $
//
// Copyright Information:
// Copyright (C) 1998 Lawrence Berkeley National Laboratory
// Copyright (C) 1998-2004 California Institute of Technology
//
//------------------------------------------------------------------------
//-----------------
// C/C++ Headers --
//-----------------
#include <assert.h>
#include <iostream>
//------------------------------------
// Collaborating Class Declarations --
//------------------------------------
class ErrStream;
class ErrOptParser;
template <class T> class ErrOptRef;
// Use the ErrMsg and ErrLogging macros for interacting with the error logger
// in a syntactically economical way.
// The next two macros allow the substitution of the value of the
// __LINE__ macro as a quoted character string instead of an integer.
// As odd as this may seem, it's a well-established ISO C trick.
// 1) replaced by its argument, treated as a quoted string, without any
// nested expansions applied (they are suppressed by the "#" operator).
#define ERRLINE_HACK_1(line) #line
// 2) allows its argument (which will be "__LINE__") to have macro expansion
// performed on it. Hence HACK_2(__LINE__) becomes, e.g., HACK_1(76).
#define ERRLINE_HACK_2(line) ERRLINE_HACK_1(line)
#ifdef ErrMsg
#undef ErrMsg
#endif
#define ErrMsg(sev) ErrLog::msg( ErrLog::sev, __FILE__ "(" ERRLINE_HACK_2(__LINE__) ")", 0 )
#ifdef ErrLogging
#undef ErrLogging
#endif
#define ErrLogging(sev) ErrLog::logging( ErrLog::sev, __FILE__ "(" ERRLINE_HACK_2(__LINE__) ")", 0 )
// [June 2002 note] The old versions of these macros expanded to
// ( ErrLog::sev, __FILE__, __LINE__ ) and so invoked the (..., int) forms
// of msg() and logging(). But at run time these forms were immediately
// vectored, by converting the code to a string, into the (..., const char*)
// forms, in which then in practice in all relevant ErrLog implementations the
// "code" string, containing the line number, was appended to the facility.
//
// The new forms of these macros preserve this behavior -- the line number
// is concatenated to the file name -- on the theory that the line number
// makes a silly code number and that the file+line combination is
// reasonable to treat as a unit.
// The actual class
class ErrLog {
public:
/**
* Message severity levels.
*/
enum Severity { debugging=-1,
trace=0,
routine,
warning,
error,
severe,
fatal,
MinSeverity=debugging,
MaxSeverity=fatal };
// fatal: A condition exists that casts doubt on the integrity
// of processing and the reliability of any results.
// No recovery strategy can be attempted, because the
// state of the program may be indeterminate.
//
// It is intended that "fatal" errors be reported
// primarily when it is likely that the condition was
// caused by incorrect code, or when the root cause cannot
// be determined. Dealing with the error is likely to
// require debugging or other expert investigation.
//
// In most implementations, this will be configured to
// result in application termination with ::abort()
// immediately after the error message is completed with
// "endmsg", producing a core dump usable to obtain a
// traceback.
//
// Programmers should generally not call ::abort() or
// ::exit() themselves following the message.
// severe: A condition exists such that the general ability of
// the program to continue work is compromised: the
// present computation and most or all subsequent ones
// are likely to fail or produce erroneous results.
//
// It is intended that "severe" errors be reported
// primarily when external conditions (command line
// arguments, control files, data files, the contents of
// databases) are identified to be incompatible with
// proceeding. The programmer should ensure that the
// message written is as informative as possible.
//
// In most implementations, this will be configured to
// result in application termination immediately after
// the error message is completed with "endmsg" and
// delivered, with a non-zero exit status. The ErrLog
// implementation is free to determine the exit status
// to use, from the range 1-126. It may take the "code"
// value from the ErrLog::msg( , , code ) into account.
//
// Programmers should generally not call ::abort() or
// ::exit() themselves following the message.
// error: A condition exists such that requested result or
// action can not be produced. However, future
// processing may be able to succeed.
// warning: The result is produced, but may not be
// what's desired due to an unexpected condition
// routine: Nothing known to be wrong with the result;
// messages that are always produced in normal
// operation
// trace: Messages about the flow of program control
// and which optional operations took place.
// (This is the default if nothing is defined)
// debugging: Information in addition to the above
/**
* This constant is the exit code to be used when a message severity
* is such that an exit(!=0) -- as opposed to an abort() -- is merited,
* but no message-specific exit code can be determined from the
* message parameters.
*/
enum { DefaultExitCode=125 };
//-----------------------------------------------------------------------
// Static public member functions ---------------------------------------
//-----------------------------------------------------------------------
public:
// These member functions are the public interface to error logging.
/**
* Returns a stream to which to write a message, with the parameters
* given. The message must be terminated later by performing the
* "<< endmsg" operation on the resulting stream. Actual output may
* not occur until the endmsg is executed. The meaning of the "facility"
* and "code" parameters is not defined by the ErrLog base class, nor is
* is guaranteed that their values will be reflected in any output
* generated for the message.
*
* The "facility" pointer must be guaranteed by the caller to remain
* valid until the message is completed with "endmsg". (I.e., this
* function is not guaranteed to make a copy of the string.)
*/
static std::ostream& msg( ErrLog::Severity severity,
const char* facility,
int code );
/**
* DEPRECATED
* Backward-compatibility function for an old API.
* Calls through to msg( severity, facilty + code, 0 )
* Do not use in new code.
*/
static std::ostream& msg( ErrLog::Severity severity,
const char* facility,
const char* code );
/**
* Tests whether actual logging output is enabled for a specific set
* of message parameters. This function should be used before sending
* complex output to the result of ErrMsg() or ErrLog::msg(), to avoid
* the cost of executing the stream insertion operations (binary-to-
* string conversions) for the message, only to discard their output.
*/
inline
static bool logging( ErrLog::Severity severity,
const char* facility,
int code );
/**
* DEPRECATED
* Backward-compatibility function for an old API.
* Calls through to logging( severity, facilty + code, 0 )
* Do not use in new code.
*/
static bool logging( ErrLog::Severity severity,
const char* facility,
const char* code );
// The following are options controlling the global configuration of
// the static "front end" to error logging.
/**
* Disables the automatic warning message generated when a new ErrLog::msg()
* call is made before the previous one has been terminated with "endmsg".
* The use of this option is *strongly* discouraged; the correct response
* to such warnings is to fix the nested messages.
*/
static void turnOffWarnings();
// The following are utility functions that are probably of interest only
// implementations (i.e., could be protected) but expose no internals and
// are harmless, and maybe useful, to make public.
/**
* Returns a static string corresponding to the enum member name of a
* severity level. I.e., severityName(ErrLog::error) == "error".
*/
static const char* severityName( ErrLog::Severity );
/**
* Returns a single uppercase letter corresponding to the enum member name
* of a severity level. I.e., severityName(ErrLog::error) == 'E'.
*/
static char severityLetter( ErrLog::Severity );
//-----------------------------------------------------------------------
// Instance public member functions -------------------------------------
//-----------------------------------------------------------------------
public:
/**
* Provides parsing of a comma-delimited list of error logger
* behavior control options, in getsubopt() format. The effects of
* the parsing depend on the specific ErrLog implementation and are
* established by it at constructor time using the _errOptParser()
* and _configureOptions() methods.
*/
bool parseOpts( const char* optarg );
//-----------------------------------------------------------------------
// Friendship declarations ----------------------------------------------
//-----------------------------------------------------------------------
friend class ErrStream;
//-----------------------------------------------------------------------
// Instance protected member functions ----------------------------------
//-----------------------------------------------------------------------
protected:
// These members provide a basic set of functions for dealing with a
// specific instance of ErrLog or a subclass. They are really intended
// only for use in configuring the active instance just after it's been
// created.
/**
* Protected constructor, for use in initializing subclasses.
*
* @param minSeverity Minimum severity of messages that will be logged
* by the default implementation.
*/
ErrLog( ErrLog::Severity minSeverity = ErrLog::debugging );
/**
* A virtual destructor is provided, but note that the quasi-singleton
* design of this class cannot guarantee that the active ErrLog instance
* will be deleted at application termination.
*/
virtual ~ErrLog();
// Functions used with ErrOptParser.
virtual bool _configureOptions();
ErrOptParser& _errOptParser() { return *_itsErrOptParser; }
//-----------------------------------------------------------------------
// Instance protected virtual member functions --------------------------
//-----------------------------------------------------------------------
protected:
// These members provide the polymorphic interface for customizing the
// behavior of an ErrLogger implementation.
/**
* Establishes an std::ostream that is to be used for logging message text,
* to be terminated with "endmsg". Pure virtual.
*/
virtual ErrStream& doMsg( ErrLog::Severity severity,
const char* facility,
int code ) = 0;
/**
* Callback from ErrStream when a message has been completed, allowing
* the logger to decide what to do.
*
* @param text The full formatted message text, if the ErrStream is a
* "buffering" stream, or 0 (null pointer) if it is a
* "wrapper" stream, with output actually appearing as
* each stream-output (<<) operation happens.
* @param stream The ErrStream to which the message had been directed.
* It's provided so that end-of-message output (std::endl or
* something more) can be written if appropriate.
*/
virtual void doEndmsg( const char* text, ErrStream& stream ) = 0;
/**
* Tests whether a message will actually be logged for a particular
* set of message parameters. A default implementation is provided,
* based only on a test of the severity w.r.t. a minimum level, a
* static member of the ErrLog base class.
*
* The sort of thing a subclass might do here is apply a "verbosity"
* control in addition to the severity test, perhaps suppressing
* repeated messages with the same parameters.
*/
virtual bool doLogging( ErrLog::Severity severity,
const char* facility,
int code );
//-----------------------------------------------------------------------
// Static protected member functions ------------------------------------
//-----------------------------------------------------------------------
protected:
// These members provide tools for ErrLog implementations to use.
/**
* ErrLog is a form of singleton. Polymorphism of its static methods is
* arranged by calling implementation instances through this pointer.
*/
inline static ErrLog* _implementation() { return _implInstance; }
/**
* ErrLog is a form of singleton. The constructor of any subclass must
* register itself as the active instance by calling this function.
*/
inline static void _setImplementation( ErrLog* implementation );
/**
* Get the appropriate default stream for a given severity level.
* The facility and code arguments are not used.
*/
static ErrStream* _getDefaultStream( ErrLog::Severity, const char*, int );
/**
* Apply the logging test for a given severity level.
* The facility and code arguments are not used.
*/
inline static bool _getDefaultLogging( ErrLog::Severity, const char*, int );
/**
* Write a set of message parameters through into an ErrStream.
* This function exists so that subclasses of ErrLog can benefit
* from its friendship relationship with ErrStream.
*/
static void _setParameters( ErrStream&,
ErrLog::Severity, const char*, int );
/**
* Evaluated and executes the default termination strategy for errors:
* abort() on fatal, exit(!=0) on severe, with the exit code derived from
* the message's "code" value.
*/
static void _defaultTermination( ErrLog::Severity severity,
int code );
/**
* Tests the anticipated behavior of the default termination strategy.
* Available for use by implementations that need to know whether a
* termination will result before deciding on the disposition of a
* message.
*
* @return 0 if termination will not occur, non-zero if it will.
* Negative if by signal (SIGABRT), positive if by exit(!=0).
*
* @see QtrErrLog
*/
static int _getDefaultTermination( ErrLog::Severity severity,
int code );
//-----------------------------------------------------------------------
// Static private member functions --------------------------------------
//-----------------------------------------------------------------------
private:
// These functions provide implementation details.
static void _executeDefaultTermination( int value );
//-----------------------------------------------------------------------
// Static protected member data -----------------------------------------
//-----------------------------------------------------------------------
protected:
// data members for the static front end and default implementation
// These appear to be used in implementations. A future cleanup pass
// may be able to convert them all to private.
static ErrStream* _myStreamCout;
static ErrStream* _myStreamCerr;
static ErrStream* _myDevnull;
static Severity _minSeverity;
//-----------------------------------------------------------------------
// Static private member data -------------------------------------------
//-----------------------------------------------------------------------
private:
// Singleton polymorphic implementation instance.
static ErrLog* _implInstance;
// data members for the static front end and default implementation
static bool _nestedWarnings;
private:
bool _useStdio;
// Contained by reference to avoid introducing header file dependencies:
ErrOptRef<bool>* _useStdioOpt;
ErrOptParser* _itsErrOptParser;
// dis-allow copy construction and assignment
ErrLog( const ErrLog& );
ErrLog& operator=( const ErrLog& );
};
// Friends of ErrStream that are needed in implementing the "endmsg" feature.
void endmsg(ErrStream& es); // declare
std::ostream& operator<<(std::ostream& os, void (*fp)(ErrStream & es) );
// --------------------------------------------------------------------------
// Inline implementations ---------------------------------------------------
// --------------------------------------------------------------------------
inline bool
ErrLog::logging( ErrLog::Severity severity,
const char* facility,
int code )
{
return ( _implementation() != 0
? _implementation()->doLogging( severity, facility, code )
: ErrLog::_getDefaultLogging( severity, facility, code ) );
}
inline void
ErrLog::_setImplementation( ErrLog* implementation )
{
// "There can only be one" (or zero -- we can reset to the default).
assert( implementation == 0 || _implementation() == 0 );
// If the assertion is compiled away, this call is simply ignored.
if ( implementation == 0 || _implementation() == 0 ) {
_implInstance = implementation;
}
}
inline bool
ErrLog::_getDefaultLogging( ErrLog::Severity severity,
const char*, // unused
int ) // unused
{
return ( severity >= _minSeverity );
}
#endif // ERRLOG_HH