casacore
Main Page
Related Pages
Modules
Namespaces
Classes
Files
File List
File Members
All
Classes
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Friends
Macros
Groups
Pages
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
LogOrigin.h
aips.h
LogFilter.h
LogMessage.h
LogIO.h
LogSink.h
Generated by
1.8.5