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