casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Logging.h
Go to the documentation of this file.
00001 //# Logging.h: Send, record, and filter informational messages
00002 //# Copyright (C) 1996,1997,2004
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //#
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //#
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //#
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //#
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //# $Id: Logging.h 20551 2009-03-25 00:11:33Z Malte.Marquarding $
00027 
00028 #ifndef CASA_LOGGING_H
00029 #define CASA_LOGGING_H
00030 
00031 #include <casa/Logging/LogMessage.h>
00032 #include <casa/Logging/LogOrigin.h>
00033 #include <casa/Logging/LogSink.h>
00034 #include <casa/Logging/LogFilter.h>
00035 //#include <aips/LogTables/TableLogSink.h>
00036 #include <casa/Logging/LogIO.h>
00037 
00038 namespace casa { //# NAMESPACE CASA - BEGIN
00039 
00040 // <module> 
00041 //
00042 // <summary> 
00043 // Send, record, and filter informational messages.
00044 // </summary>
00045 
00046 // <prerequisite>
00047 //   <li> General AIPS++ utility classes, such as String.
00048 // </prerequisite>
00049 
00050 // <reviewed reviewer="wbrouw" date="1996/08/21" demos="dLogging.cc" tests="tLogging.cc">
00051 // </reviewed>
00052 
00053 // <etymology>
00054 // Logging, as in "log book", or "processing log."
00055 // </etymology>
00056 //
00057 // <synopsis> 
00058 // The classes in the logging module have two essential purposes:
00059 // <ol>
00060 // <li> To attach processing logs to datasets to retain a permanent history of
00061 //      informational messages that describe how the dataset arrived at its
00062 //      present state; and
00063 // <li> To inform the user about the progress and decisions made by various
00064 //      algorithms, such as those used in the Measures system.
00065 // </ol>
00066 //
00067 // The two fundamental classes in the Logging module are the
00068 // <linkto class="LogMessage">LogMessage</linkto> and
00069 // <linkto class="LogSink">LogSink</linkto> classes.
00070 // However, the class which is most of interest to application programmers is
00071 // the <linkto class=LogIO>LogIO</linkto> class since it forms the usual
00072 // interface to logging.
00073 //
00074 // A <src>LogMessage</src> consists of an informational message tagged with the
00075 // time, a priority (<src>DEBUGGING, NORMAL,</src>, <src>WARN</src>, or
00076 // <src>SEVERE</src>) and the source code location of the origin of the message
00077 // (for use in debugging primarily).
00078 //
00079 // The <src>LogSink</src> is used to send the <src>LogMessage</src> to its
00080 // destinations. Usually the message will be sent to both a global sink,
00081 // intended for user information (e.g., a GUI window), and to a sink associated
00082 // with the dataset(s) which are being modified. In practice, the application
00083 // programmer does not need to worry about where the global messages go, that
00084 // policy is implemented by the Tasking system. In practice, global messages
00085 // will be sent to Glish, where they will appear in a GUI, unless Glish is
00086 // not available, in which case SEVERE messsages (only) will be sent to
00087 // stdout. However, the principle is that "ordinary" application programmers
00088 // shouldn't worry about the details of the global sink - they should just
00089 // use it.
00090 //
00091 // A <linkto class="LogFilter">LogFilter</linkto> can be used to filter
00092 // messages (based on priority only at the moment) before they are sent to
00093 // their appropriate sink(s).
00094 //
00095 // The <linkto class="LogIO">LogIO</linkto> class puts an ostream like
00096 // interface on top of the loggins system. Basically, the application
00097 // programmer just has to create messages using and <src>os << items</src>
00098 // type interface.
00099 //
00100 // The first issue that the application programmer has to decide is whether
00101 // to use logging at all, or if instead he should put his messages into a
00102 // <linkto class="String">String</linkto> or an <src>ostream</src>. It is
00103 // never wrong to use log messages, however it is reasonable for low level
00104 // classes to use <src>String</src>s or <src>ostream</src>s, since the
00105 // caller of that class will have the opportunity to put the text in a log
00106 // message if he decides that's the most appropriate thing to do. Note that
00107 // it is always wrong to write directly to <src>cout</src> or
00108 // <src>cerr</src> (other
00109 // then for debugging) - use an <src>ostream</src>, so the caller can replace
00110 // it with, for example, an <src>ostringstream</src>.
00111 //
00112 // Once you decide to use logging, the application programmer only has
00113 // to decide at every location he wants to log:
00114 // <ol>
00115 //     <li> What content do you want the message to have; and
00116 //     <li> what priority does the message have (DEBUGGING, NORMAL, WARN, SEVERE).
00117 // </ol>
00118 // Schematically, application programmers would use the logging system as
00119 // follows:
00120 // <srcBlock>
00121 // #include <casa/Logging.h>
00122 // ...
00123 // void MyClass:myFunction(LogIO &os)
00124 // {
00125 //    os << LogIO::NORMAL << LogOrigin("MyClass", "myFunction()", WHERE);   // 1
00126 //    ...
00127 //    os << WHERE << "An informative message") << LogIO::POST;              // 2
00128 //    if (error()) {
00129 //        os << WHERE << LogIO::SEVERE << "Error!" << LogIO::POST;          // 3
00130 //        sink.post(msg);
00131 //        ...
00132 //    }
00133 // }
00134 // </srcBlock>
00135 // <ol>
00136 //    <li> Set up the location where log messages come from. WHERE will expand
00137 //         into the file name and line number (useful for debugging). Set the
00138 //         priority to NORMAL (this is the default, but you don't know what
00139 //         the state of <src>os</src> is when it is passed in to this function).
00140 //    <li> Set the message and the new line number (optional but encouraged) and
00141 //         post it.
00142 //    <li> Change the priority to SEVERE and post an error message. 
00143 // </ol>
00144 //
00145 // When a dataset is created from several other datasets, their input
00146 // "histories" should be merged if possible. This can be done if the
00147 // local log sink is in fact a Table. The way you do this is by interrogating
00148 // the local sink to find out if it is in fact a TableLogSink. If it is, you
00149 // can use a concatenate method of TableLogSink. Schematically this would be
00150 // implemented as follows in some DataSet class that has a logSink method that
00151 // returns a LogIO reference:
00152 // <srcBlock>
00153 // void merge(DataSet &out, const DataSet &in1, const DataSet &in2) {
00154 //     ... copy the data from in1 and in2 to out
00155 //     if (out.logSink().localSink().isTableLogSink()) { // can write to out
00156 //         if (in1.logSink().localSink().isTableLogSink()) {
00157 //             out.logSink().localSink().castToTableLogSink().concatenate(
00158 //                  in1.logSink().localSink().castToTableLogSink());
00159 //     }
00160 //     if (... the same for in2 ...)
00161 // }
00162 // </srcBlock>
00163 // Of course, DataSet might provide some convenience function for merging
00164 // histories. However the point is that given a sink, you can safely determing
00165 // whether or not it is in fact a TableLogSink, and if it is you can call
00166 // its concatenate function, which takes another TableLogSink.
00167 // </synopsis> 
00168 //
00169 // <example>
00170 // The following example code is checked into the system as
00171 // <src>dLogging.cc</src>. It is found in the Logging test directory.
00172 //
00173 // <srcblock>
00174 // class DataClass
00175 // {
00176 // public:
00177 //   DataClass(const IPosition &shape, const LogSink &sink);  // 1
00178 //   void set(Int toWhat);                                    // 2
00179 //   LogIO   &sink() return os_p;}                            // 3
00180 //   Array<Int> &data() {return data_p;}                      // 4
00181 //   const Array<Int> &data() const {return data_p;}          // 5
00182 // private:                                                   // 6
00183 //   Vector<Int> data_p;                                      // 7
00184 //   LogSink log_sink_p;                                      // 8
00185 //   LogIO os_p;                                              // 9
00186 // };
00187 // </srcblock>
00188 //
00189 // This toy class is meant to represent one which is to have "attached" logging
00190 // information. Generally, these classes would be fairly high level
00191 // astronomical classes, e.g. <src>Image</src>, not <src>Array</src>. Note that
00192 // only operations which change the data should be logged in the internal log.
00193 // Operations which only read the data should be logged either globally, or in
00194 // the class that is taking the results and modifying its own data.
00195 //
00196 // <dl compact>
00197 // <dt>1.
00198 // <dd> Depending on the application, the LogSink to be used might
00199 // either be handed in to the class, as is the case here, or it might
00200 // be created by the class.  For example, a <src>MeasurementSet</src>
00201 // will have a processing log table with a known name.
00202 // <dt> 2.
00203 // <dd> A sample function that changes the state of the class. Here,
00204 //      it just sets all the elements of the internal array to 
00205 //      <src>toWhat</src>.
00206 // <dt> 3.
00207 // <dd> Return the LogIO that is used by this object. A member function like this
00208 //      should be provided for use by global functions which manipulate the object.
00209 //      Note that it is non-const --- the internal sink should be modified only
00210 //      by functions which CHANGE the object, otherwise the global sink should be
00211 //      used.
00212 // <dt> 4.
00213 // <dd> Return the internal data. Arguably this should be logged at at least
00214 //      DEBUGGING level.
00215 // <dt> 5.
00216 // <dd> Non-const version of the above. Note that it should not be logged since
00217 //      the state cannot be changed with this function.
00218 // <dt> 7.
00219 // <dd> The internal data member.
00220 // <dt> 8.
00221 // <dd> The location to which log mesages are sent.
00222 // <dt> 9.
00223 // <dd> The LogIO object that will be the actual interface to the logging 
00224 //      system.
00225 // </dl>
00226 //
00227 // <srcblock>
00228 // DataClass::DataClass(const IPosition &shape, const LogSink &sink)
00229 //   : log_sink_p(sink), os_p(log_sink_p)                                     // 1
00230 // {                                                                          // 2
00231 //   os_p << LogOrigin("DataClass",                                           // 3
00232 //                "DataClass(const IPosition &shape, const LogSink &sink)");  // 4
00233 //                                                                            // 5
00234 //   if (shape.nelements() != 1) {                                            // 6
00235 //     os_p << LogIO::SEVERE << WHERE <<                                      // 7
00236 //       "Illegal Shape! Must be one dimensional." << LogIO::EXCEPTION;       // 8
00237 //   }                                                                        // 9
00238 //                                                                            // 10
00239 //   data_p.resize(shape(0));                                                 // 11
00240 //   os_p << "Inital shape " << shape << "and value 2" <<                     // 12
00241 //       LogIO::NORMAL << LogIO::POST;                                        // 13
00242 //                                                                            // 14
00243 //   set(2);                                                                  // 15
00244 // }
00245 // </srcblock>
00246 // <dl compact>
00247 // <dt> 1.
00248 // <dd> The private <src>LogSink</src> data member is initialized with one that 
00249 //      the caller provides. Note that LogSink uses reference semantics, so
00250 //      that if another "copy" of the sink is made then all the log messages
00251 //      will go to the same place. For example:
00252 //      <srcblock>
00253 //          LogSink a("mylogtable");
00254 //          LogSink b(a);
00255 //          LogSink c;
00256 //          c = a;
00257 //          ...
00258 //          c.post(...);  // ends up in mylogtable
00259 //          ...
00260 //          b.post(...);  // as does this
00261 //      </srcblock>
00262 //      This can be useful if several classes might be modifying the same data, 
00263 //      or if a data is spread over several objects.
00264 //
00265 //      Also, os_p is intialized from the sink.
00266 // <dt> 3.
00267 // <dd> For a member function, the first argument to LogOrigin is the class name.
00268 // <dt> 4.
00269 // <dd> The next argument is the function name. You should use the full name with
00270 //      arguments so that you can use the argument name in your messages. Leave
00271 //      off the return type. Cutting and pasting is easier than typing!
00272 // <dt> 7.
00273 // <dd> WHERE is a predefined macro that gives the file name and line number.
00274 // <dt> 8.
00275 // <dd> Create a SEVERE level error message, post it and throw an exception.
00276 // <dt> 11.
00277 // <dd> This will post the message locally and globally, and then throw
00278 // an exception. Another possibility would be to call
00279 // <src>postGloballyThenThrow()</src> if you only wanted to send the
00280 // message to the global sink (for example, if the object is hopelessly
00281 // corrupted, or if the problem occurs in a read-only operation). The
00282 // thrown exception is an <src>AipsError</src>. The
00283 // <src>post*Throw()</src> functions will always set the priority to
00284 // <src>SEVERE</src>, however it doesn't hurt to show your intentions
00285 // <dt> 12.
00286 // <dd> Create and send a NORMAL priority message.
00287 // <dt> 15.
00288 // <dd> Call <src>set()</src> from the constructor to give the data values 
00289 //      an initial value.
00290 // </dl>
00291 //
00292 // <srcblock>
00293 // void DataClass::set(Int toWhat)
00294 // {
00295 //   os_p << LogIO::NORMAL << LogOrigin("DataClass", "set(Int toWhat)");      // 1
00296 //   os_p << "Setting data values to " << toWhat << WHERE << LogIO::POST;     // 2
00297 //   uInt n = data_p.nelements();                                             // 3
00298 //   for (uInt i=0; i < n; i++) {                                             // 4
00299 // #ifdef AIPS_DEBUG                                                          // 5
00300 //     os_p << LogIO::DEBUGGING << WHERE <<                                   // 6
00301 //       "Setting element  " << i << " to " << toWhat << LogIO::POST;         // 7
00302 // #endif                                                                     // 8
00303 //     data_p(i) = toWhat;                                                    // 9
00304 //   }
00305 // }
00306 // </srcblock>
00307 //
00308 // <dl compact>
00309 // <dt> 2.
00310 // <dd> This and the previous line set up and send a normal priority log message
00311 //      much as we did previously.
00312 // <dt> 7.
00313 // <dd> LogMessages are relatively expensive to produces and consume. Use of 
00314 //      them in a very tight loop should either be <src>ifdef</src>'d out as 
00315 //      in this example, or like:
00316 //      <srcblock>
00317 //      if (aips_debug_on) {
00318 //      ... set up and send log message ...
00319 //      }
00320 //      </srcblock>
00321 //      The advantage of this code is that it's always available - so, for 
00322 //      example, you can turn it on and off by manipulating the global variable
00323 //      <src>aips_debug_on</src>. However very tight loops cannot even afford 
00324 //      this extra <src>if</src>, and should prefer the <src>ifdef</src>.
00325 //
00326 //      Normally the <src>DEBUGGING</src> messages are "boring but low-volume",
00327 //      and you should just send them normally.
00328 // </dl>
00329 //
00330 // <srcblock>
00331 // void square(DataClass &object)
00332 // {
00333 //   object.sink() << LogIO::NORMAL << WHERE <<                              // 1
00334 //     LogOrigin("square(DataClass &object)") << "Squaring data elements"    // 2
00335 //      << LogIO::POST;                                                    // 3
00336 //   object.data() *= object.data();                                         // 4
00337 // }
00338 // </srcblock>
00339 //
00340 // This function shows how a global function that modifies an object can send
00341 // log messages to that objects <src>LogSink</src> using a function of that
00342 // object to get access to its sink.
00343 //
00344 // <srcblock>
00345 // float sum(const DataClass &object)
00346 // {
00347 //   LogIO global(LogOrigin("sum(const DataClass &object)"));        // 1
00348 //   float theSum = sum(object.data());                              // 2
00349 //   global << WHERE << "Sum of object is: " << theSum;              // 3 
00350 //   return theSum;                                                  // 4
00351 // }
00352 // </srcblock>
00353 // This is an example of a global function that only reads -- does not change --
00354 // an object.
00355 // <dl>
00356 // <dt> 3.
00357 // <dd> Since we are not changing the data object, we only post the message
00358 //      globally, we don't write it to the data object's log sink. The caller
00359 //      of <src>sum()</src> might log the message somewhere else if the return
00360 //      value is used to modify data in some other object. Instead we send it
00361 //      to the global sink. Here we don't POST the message ourselves, we rely
00362 //      on the LogIO destructor to do it for us.
00363 // </dl>
00364 //
00365 // <srcblock>
00366 // int main()
00367 // {
00368 //     LogSink::globalSink().filter(LogMessage::DEBUGGING);           // 1
00369 //     LogSink logger(LogMessage::NORMAL, "dLogging_messages_tmp");   // 2
00370 //                                                                    // 3
00371 //     IPosition legalShape(1, 10);                                   // 4
00372 //     DataClass dc(legalShape, logger);                              // 5
00373 //                                                                    // 6
00374 //     square(dc);                                                    // 7
00375 //                                                                    // 8
00376 //     Float total = sum(dc);                                         // 9
00377 //                                                                    // 10
00378 //     return 0;                                                      // 11
00379 // }
00380 // </srcblock>
00381 // <dl compact>
00382 // <dt> 1.
00383 // <dd> Change the priority of messages to display on the global sink's 
00384 //      filter to
00385 //      <src>DEBUGGING</src> from the default <src>NORMAL</src>. The default
00386 //      global sink logs to cerr. The global sink can be replaced with
00387 //      <src>LogSink::globalSink()</src>.
00388 // <dt> 2.
00389 // <dd> Create the sink that we are going to use. This constructor will use
00390 //      a <linkto class="Table">Table</linkto>. If the table doesn't exist
00391 //      it will be created. If it does exist, new log messages will be appended
00392 //      to the end.
00393 // <dt> 5.
00394 // <dd> Create an object with the provided sink. The alternative strategy, which
00395 //      will be used with classes like
00396 //      <linkto class="MeasurementSet">MeasurementSet</linkto> is for the object
00397 //      to make it's own <src>LogSink</src> if it knows where it wants its 
00398 //      messages to go.
00399 // <dt> 7.
00400 // <dd> Changes the data - log messages go to its local sink.
00401 // <dt> 9.
00402 // <dd> Reads the data - log messages go only to the global sink.
00403 // </dl>
00404 
00405 // </example>
00406 //
00407 // <motivation>
00408 // <ol>
00409 // <li> Attaching informational messages to datasets to describe their processing
00410 // history.
00411 // <li> Informational messages to inform the user about the progress and 
00412 //      parameters of algorithms - for example those used for reference frame
00413 //      conversions in the Measures module.
00414 // </ol>
00415 // </motivation>
00416 
00417 // <todo asof="1997/01/19">
00418 //   <li> More filtering options?
00419 // </todo>
00420 
00421 // </module>
00422 
00423 
00424 } //# NAMESPACE CASA - END
00425 
00426 #endif