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

Generated on 31 Aug 2016 for casa by  doxygen 1.6.1