casacore
Loading...
Searching...
No Matches
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
37namespace 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
423} //# NAMESPACE CASACORE - END
424
425#endif
this file contains all the compiler specific defines
Definition mainpage.dox:28