casacore
casa
Logging.h
Go to the documentation of this file.
1
//# Logging.h: Send, record, and filter informational messages
2
//# Copyright (C) 1996,1997,2004
3
//# Associated Universities, Inc. Washington DC, USA.
4
//#
5
//# This library is free software; you can redistribute it and/or modify it
6
//# under the terms of the GNU Library General Public License as published by
7
//# the Free Software Foundation; either version 2 of the License, or (at your
8
//# option) any later version.
9
//#
10
//# This library is distributed in the hope that it will be useful, but WITHOUT
11
//# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
//# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13
//# License for more details.
14
//#
15
//# You should have received a copy of the GNU Library General Public License
16
//# along with this library; if not, write to the Free Software Foundation,
17
//# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18
//#
19
//# Correspondence concerning AIPS++ should be addressed as follows:
20
//# Internet email: aips2-request@nrao.edu.
21
//# Postal address: AIPS++ Project Office
22
//# National Radio Astronomy Observatory
23
//# 520 Edgemont Road
24
//# Charlottesville, VA 22903-2475 USA
25
//#
26
//# $Id$
27
28
#ifndef CASA_LOGGING_H
29
#define CASA_LOGGING_H
30
31
#include <casacore/casa/aips.h>
32
33
#include <casacore/casa/Logging/LogMessage.h>
34
#include <casacore/casa/Logging/LogOrigin.h>
35
#include <casacore/casa/Logging/LogSink.h>
36
#include <casacore/casa/Logging/LogFilter.h>
37
#include <casacore/casa/Logging/LogIO.h>
38
39
namespace
casacore
{
//# NAMESPACE CASACORE - BEGIN
40
41
// <module>
42
//
43
// <summary>
44
// Send, record, and filter informational messages.
45
// </summary>
46
47
// <prerequisite>
48
// <li> General Casacore utility classes, such as String.
49
// </prerequisite>
50
51
// <reviewed reviewer="wbrouw" date="1996/08/21" demos="dLogging.cc" tests="tLogging.cc">
52
// </reviewed>
53
54
// <etymology>
55
// Logging, as in "log book", or "processing log."
56
// </etymology>
57
//
58
// <synopsis>
59
// The classes in the logging module have two essential purposes:
60
// <ol>
61
// <li> To attach processing logs to datasets to retain a permanent history of
62
// informational messages that describe how the dataset arrived at its
63
// present state; and
64
// <li> To inform the user about the progress and decisions made by various
65
// algorithms, such as those used in the Measures system.
66
// </ol>
67
//
68
// The two fundamental classes in the Logging module are the
69
// <linkto class="LogMessage">LogMessage</linkto> and
70
// <linkto class="LogSink">LogSink</linkto> classes.
71
// However, the class which is most of interest to application programmers is
72
// the <linkto class=LogIO>LogIO</linkto> class since it forms the usual
73
// interface to logging.
74
//
75
// A <src>LogMessage</src> consists of an informational message tagged with the
76
// time, a priority (<src>DEBUGGING, NORMAL,</src>, <src>WARN</src>, or
77
// <src>SEVERE</src>) and the source code location of the origin of the message
78
// (for use in debugging primarily).
79
//
80
// The <src>LogSink</src> is used to send the <src>LogMessage</src> to its
81
// destinations. Usually the message will be sent to both a global sink,
82
// intended for user information (e.g., a GUI window), and to a sink associated
83
// with the dataset(s) which are being modified. In practice, the application
84
// programmer does not need to worry about where the global messages go, that
85
// policy is implemented by the Tasking system. In practice, global messages
86
// will be sent to Glish, where they will appear in a GUI, unless Glish is
87
// not available, in which case SEVERE messsages (only) will be sent to
88
// stdout. However, the principle is that "ordinary" application programmers
89
// shouldn't worry about the details of the global sink - they should just
90
// use it.
91
//
92
// A <linkto class="LogFilter">LogFilter</linkto> can be used to filter
93
// messages (based on priority only at the moment) before they are sent to
94
// their appropriate sink(s).
95
//
96
// The <linkto class="LogIO">LogIO</linkto> class puts an ostream like
97
// interface on top of the loggins system. Basically, the application
98
// programmer just has to create messages using and <src>os << items</src>
99
// type interface.
100
//
101
// The first issue that the application programmer has to decide is whether
102
// to use logging at all, or if instead he should put his messages into a
103
// <linkto class="String">String</linkto> or an <src>ostream</src>. It is
104
// never wrong to use log messages, however it is reasonable for low level
105
// classes to use <src>String</src>s or <src>ostream</src>s, since the
106
// caller of that class will have the opportunity to put the text in a log
107
// message if he decides that's the most appropriate thing to do. Note that
108
// it is always wrong to write directly to <src>cout</src> or
109
// <src>cerr</src> (other
110
// then for debugging) - use an <src>ostream</src>, so the caller can replace
111
// it with, for example, an <src>ostringstream</src>.
112
//
113
// Once you decide to use logging, the application programmer only has
114
// to decide at every location he wants to log:
115
// <ol>
116
// <li> What content do you want the message to have; and
117
// <li> what priority does the message have (DEBUGGING, NORMAL, WARN, SEVERE).
118
// </ol>
119
// Schematically, application programmers would use the logging system as
120
// follows:
121
// <srcBlock>
122
// #include <casacore/casa/Logging.h>
123
// ...
124
// void MyClass:myFunction(LogIO &os)
125
// {
126
// os << LogIO::NORMAL << LogOrigin("MyClass", "myFunction()", WHERE); // 1
127
// ...
128
// os << WHERE << "An informative message") << LogIO::POST; // 2
129
// if (error()) {
130
// os << WHERE << LogIO::SEVERE << "Error!" << LogIO::POST; // 3
131
// sink.post(msg);
132
// ...
133
// }
134
// }
135
// </srcBlock>
136
// <ol>
137
// <li> Set up the location where log messages come from. WHERE will expand
138
// into the file name and line number (useful for debugging). Set the
139
// priority to NORMAL (this is the default, but you don't know what
140
// the state of <src>os</src> is when it is passed in to this function).
141
// <li> Set the message and the new line number (optional but encouraged) and
142
// post it.
143
// <li> Change the priority to SEVERE and post an error message.
144
// </ol>
145
//
146
// When a dataset is created from several other datasets, their input
147
// "histories" should be merged if possible. This can be done if the
148
// local log sink is in fact a Table. The way you do this is by interrogating
149
// the local sink to find out if it is in fact a TableLogSink. If it is, you
150
// can use a concatenate method of TableLogSink. Schematically this would be
151
// implemented as follows in some DataSet class that has a logSink method that
152
// returns a LogIO reference:
153
// <srcBlock>
154
// void merge(DataSet &out, const DataSet &in1, const DataSet &in2) {
155
// ... copy the data from in1 and in2 to out
156
// if (out.logSink().localSink().isTableLogSink()) { // can write to out
157
// if (in1.logSink().localSink().isTableLogSink()) {
158
// out.logSink().localSink().castToTableLogSink().concatenate(
159
// in1.logSink().localSink().castToTableLogSink());
160
// }
161
// if (... the same for in2 ...)
162
// }
163
// </srcBlock>
164
// Of course, DataSet might provide some convenience function for merging
165
// histories. However the point is that given a sink, you can safely determing
166
// whether or not it is in fact a TableLogSink, and if it is you can call
167
// its concatenate function, which takes another TableLogSink.
168
// </synopsis>
169
//
170
// <example>
171
// The following example code is checked into the system as
172
// <src>dLogging.cc</src>. It is found in the Logging test directory.
173
//
174
// <srcblock>
175
// class DataClass
176
// {
177
// public:
178
// DataClass(const IPosition &shape, const LogSink &sink); // 1
179
// void set(Int toWhat); // 2
180
// LogIO &sink() return os_p;} // 3
181
// Array<Int> &data() {return data_p;} // 4
182
// const Array<Int> &data() const {return data_p;} // 5
183
// private: // 6
184
// Vector<Int> data_p; // 7
185
// LogSink log_sink_p; // 8
186
// LogIO os_p; // 9
187
// };
188
// </srcblock>
189
//
190
// This toy class is meant to represent one which is to have "attached" logging
191
// information. Generally, these classes would be fairly high level
192
// astronomical classes, e.g. <src>Image</src>, not <src>Array</src>. Note that
193
// only operations which change the data should be logged in the internal log.
194
// Operations which only read the data should be logged either globally, or in
195
// the class that is taking the results and modifying its own data.
196
//
197
// <dl compact>
198
// <dt>1.
199
// <dd> Depending on the application, the LogSink to be used might
200
// either be handed in to the class, as is the case here, or it might
201
// be created by the class. For example, a <src>MeasurementSet</src>
202
// will have a processing log table with a known name.
203
// <dt> 2.
204
// <dd> A sample function that changes the state of the class. Here,
205
// it just sets all the elements of the internal array to
206
// <src>toWhat</src>.
207
// <dt> 3.
208
// <dd> Return the LogIO that is used by this object. A member function like this
209
// should be provided for use by global functions which manipulate the object.
210
// Note that it is non-const --- the internal sink should be modified only
211
// by functions which CHANGE the object, otherwise the global sink should be
212
// used.
213
// <dt> 4.
214
// <dd> Return the internal data. Arguably this should be logged at at least
215
// DEBUGGING level.
216
// <dt> 5.
217
// <dd> Non-const version of the above. Note that it should not be logged since
218
// the state cannot be changed with this function.
219
// <dt> 7.
220
// <dd> The internal data member.
221
// <dt> 8.
222
// <dd> The location to which log mesages are sent.
223
// <dt> 9.
224
// <dd> The LogIO object that will be the actual interface to the logging
225
// system.
226
// </dl>
227
//
228
// <srcblock>
229
// DataClass::DataClass(const IPosition &shape, const LogSink &sink)
230
// : log_sink_p(sink), os_p(log_sink_p) // 1
231
// { // 2
232
// os_p << LogOrigin("DataClass", // 3
233
// "DataClass(const IPosition &shape, const LogSink &sink)"); // 4
234
// // 5
235
// if (shape.nelements() != 1) { // 6
236
// os_p << LogIO::SEVERE << WHERE << // 7
237
// "Illegal Shape! Must be one dimensional." << LogIO::EXCEPTION; // 8
238
// } // 9
239
// // 10
240
// data_p.resize(shape(0)); // 11
241
// os_p << "Inital shape " << shape << "and value 2" << // 12
242
// LogIO::NORMAL << LogIO::POST; // 13
243
// // 14
244
// set(2); // 15
245
// }
246
// </srcblock>
247
// <dl compact>
248
// <dt> 1.
249
// <dd> The private <src>LogSink</src> data member is initialized with one that
250
// the caller provides. Note that LogSink uses reference semantics, so
251
// that if another "copy" of the sink is made then all the log messages
252
// will go to the same place. For example:
253
// <srcblock>
254
// LogSink a("mylogtable");
255
// LogSink b(a);
256
// LogSink c;
257
// c = a;
258
// ...
259
// c.post(...); // ends up in mylogtable
260
// ...
261
// b.post(...); // as does this
262
// </srcblock>
263
// This can be useful if several classes might be modifying the same data,
264
// or if a data is spread over several objects.
265
//
266
// Also, os_p is intialized from the sink.
267
// <dt> 3.
268
// <dd> For a member function, the first argument to LogOrigin is the class name.
269
// <dt> 4.
270
// <dd> The next argument is the function name. You should use the full name with
271
// arguments so that you can use the argument name in your messages. Leave
272
// off the return type. Cutting and pasting is easier than typing!
273
// <dt> 7.
274
// <dd> WHERE is a predefined macro that gives the file name and line number.
275
// <dt> 8.
276
// <dd> Create a SEVERE level error message, post it and throw an exception.
277
// <dt> 11.
278
// <dd> This will post the message locally and globally, and then throw
279
// an exception. Another possibility would be to call
280
// <src>postGloballyThenThrow()</src> if you only wanted to send the
281
// message to the global sink (for example, if the object is hopelessly
282
// corrupted, or if the problem occurs in a read-only operation). The
283
// thrown exception is an <src>AipsError</src>. The
284
// <src>post*Throw()</src> functions will always set the priority to
285
// <src>SEVERE</src>, however it doesn't hurt to show your intentions
286
// <dt> 12.
287
// <dd> Create and send a NORMAL priority message.
288
// <dt> 15.
289
// <dd> Call <src>set()</src> from the constructor to give the data values
290
// an initial value.
291
// </dl>
292
//
293
// <srcblock>
294
// void DataClass::set(Int toWhat)
295
// {
296
// os_p << LogIO::NORMAL << LogOrigin("DataClass", "set(Int toWhat)"); // 1
297
// os_p << "Setting data values to " << toWhat << WHERE << LogIO::POST; // 2
298
// uInt n = data_p.nelements(); // 3
299
// for (uInt i=0; i < n; i++) { // 4
300
// #ifdef AIPS_DEBUG // 5
301
// os_p << LogIO::DEBUGGING << WHERE << // 6
302
// "Setting element " << i << " to " << toWhat << LogIO::POST; // 7
303
// #endif // 8
304
// data_p(i) = toWhat; // 9
305
// }
306
// }
307
// </srcblock>
308
//
309
// <dl compact>
310
// <dt> 2.
311
// <dd> This and the previous line set up and send a normal priority log message
312
// much as we did previously.
313
// <dt> 7.
314
// <dd> LogMessages are relatively expensive to produces and consume. Use of
315
// them in a very tight loop should either be <src>ifdef</src>'d out as
316
// in this example, or like:
317
// <srcblock>
318
// if (aips_debug_on) {
319
// ... set up and send log message ...
320
// }
321
// </srcblock>
322
// The advantage of this code is that it's always available - so, for
323
// example, you can turn it on and off by manipulating the global variable
324
// <src>aips_debug_on</src>. However very tight loops cannot even afford
325
// this extra <src>if</src>, and should prefer the <src>ifdef</src>.
326
//
327
// Normally the <src>DEBUGGING</src> messages are "boring but low-volume",
328
// and you should just send them normally.
329
// </dl>
330
//
331
// <srcblock>
332
// void square(DataClass &object)
333
// {
334
// object.sink() << LogIO::NORMAL << WHERE << // 1
335
// LogOrigin("square(DataClass &object)") << "Squaring data elements" // 2
336
// << LogIO::POST; // 3
337
// object.data() *= object.data(); // 4
338
// }
339
// </srcblock>
340
//
341
// This function shows how a global function that modifies an object can send
342
// log messages to that objects <src>LogSink</src> using a function of that
343
// object to get access to its sink.
344
//
345
// <srcblock>
346
// float sum(const DataClass &object)
347
// {
348
// LogIO global(LogOrigin("sum(const DataClass &object)")); // 1
349
// float theSum = sum(object.data()); // 2
350
// global << WHERE << "Sum of object is: " << theSum; // 3
351
// return theSum; // 4
352
// }
353
// </srcblock>
354
// This is an example of a global function that only reads -- does not change --
355
// an object.
356
// <dl>
357
// <dt> 3.
358
// <dd> Since we are not changing the data object, we only post the message
359
// globally, we don't write it to the data object's log sink. The caller
360
// of <src>sum()</src> might log the message somewhere else if the return
361
// value is used to modify data in some other object. Instead we send it
362
// to the global sink. Here we don't POST the message ourselves, we rely
363
// on the LogIO destructor to do it for us.
364
// </dl>
365
//
366
// <srcblock>
367
// int main()
368
// {
369
// LogSink::globalSink().filter(LogMessage::DEBUGGING); // 1
370
// LogSink logger(LogMessage::NORMAL, "dLogging_messages_tmp"); // 2
371
// // 3
372
// IPosition legalShape(1, 10); // 4
373
// DataClass dc(legalShape, logger); // 5
374
// // 6
375
// square(dc); // 7
376
// // 8
377
// Float total = sum(dc); // 9
378
// // 10
379
// return 0; // 11
380
// }
381
// </srcblock>
382
// <dl compact>
383
// <dt> 1.
384
// <dd> Change the priority of messages to display on the global sink's
385
// filter to
386
// <src>DEBUGGING</src> from the default <src>NORMAL</src>. The default
387
// global sink logs to cerr. The global sink can be replaced with
388
// <src>LogSink::globalSink()</src>.
389
// <dt> 2.
390
// <dd> Create the sink that we are going to use. This constructor will use
391
// a <linkto class="Table">Table</linkto>. If the table doesn't exist
392
// it will be created. If it does exist, new log messages will be appended
393
// to the end.
394
// <dt> 5.
395
// <dd> Create an object with the provided sink. The alternative strategy, which
396
// will be used with classes like
397
// <linkto class="MeasurementSet">MeasurementSet</linkto> is for the object
398
// to make it's own <src>LogSink</src> if it knows where it wants its
399
// messages to go.
400
// <dt> 7.
401
// <dd> Changes the data - log messages go to its local sink.
402
// <dt> 9.
403
// <dd> Reads the data - log messages go only to the global sink.
404
// </dl>
405
406
// </example>
407
//
408
// <motivation>
409
// <ol>
410
// <li> Attaching informational messages to datasets to describe their processing
411
// history.
412
// <li> Informational messages to inform the user about the progress and
413
// parameters of algorithms - for example those used for reference frame
414
// conversions in the Measures module.
415
// </ol>
416
// </motivation>
417
418
// <todo asof="1997/01/19">
419
// <li> More filtering options?
420
// </todo>
421
422
// </module>
423
424
425
}
//# NAMESPACE CASACORE - END
426
427
#endif
casacore
this file contains all the compiler specific defines
Definition:
mainpage.dox:28
Generated by
1.8.16