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