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