casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
LogSink.h
Go to the documentation of this file.
00001 //# LogSink.h: Distribute LogMessages to their destination(s)
00002 //# Copyright (C) 1996,2000,2001,2003
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 //#
00027 //# $Id: LogSink.h 21051 2011-04-20 11:46:29Z gervandiepen $
00028 
00029 #ifndef CASA_LOGSINK_H
00030 #define CASA_LOGSINK_H
00031 
00032 #include <casa/aips.h>
00033 #include <casa/Logging/LogSinkInterface.h>
00034 
00035 #include <casa/Utilities/CountedPtr.h>
00036 #include <casa/Exceptions/Error.h>
00037 #include <casa/OS/Mutex.h>
00038 #include <casa/iosfwd.h>
00039 
00040 namespace casa { //# NAMESPACE CASA - BEGIN
00041 
00042 // <summary>
00043 // Distribute LogMessages to their destination(s)
00044 // </summary>
00045 
00046 // <use visibility=export>
00047 
00048 // <reviewed reviewer="wbrouw" date="1996/08/21" tests="tLogging.cc" demos="dLogging.cc">
00049 // </reviewed>
00050 
00051 // <prerequisite>
00052 // <li> <linkto class="LogMessage">LogMessage</linkto>
00053 // <li> <linkto class="LogSinkInterface">LogSinkInterface</linkto>, if you are
00054 // interested in extending the set of destinations a <src>LogMessage</src> can
00055 // be sent.
00056 // </prerequisite>
00057 //
00058 // <etymology>
00059 // Log as in "Log Book." Sink from its common usage ("source/sink") as a thing
00060 // which can accept some substance or energy.
00061 // </etymology>
00062 //
00063 // <synopsis>
00064 // The LogSink class supplies the destination for 
00065 // <linkto class="LogMessage">LogMessage</linkto>s. There are two destinations
00066 // available through the <src>LogSink</src>
00067 // <ol>
00068 // <li> A <i>global</i> destination, which is shared by all LogSinks. The global
00069 //      destination will typically be a GUI window or standard output.
00070 // <li> A <i>local</i> destination which is intended to log changes to
00071 //      particular dataset(s). The local destination will typically be an
00072 //      AIPS++ <linkto class="Table">Table</linkto>, but there is also
00073 //      a local sink for temporary storage in memory.
00074 // </ol>
00075 // Normally the <src>post()</src> member function will be called which
00076 // sends the message to both the global and local destinations, however one or
00077 // the other may be chosen via <src>LogSink::postGlobally()</src> and
00078 // <src>postLocally()</src> member functions.
00079 //
00080 // The global sink will normally be set by system library code (it defaults to
00081 // using <src>cerr</src>. The type of local sink is defined at 
00082 // construction time. Presently you can choose one of:
00083 // <ol>
00084 // <li> a <linkto class="NullLogSink">NullLogSink</linkto> which merely
00085 //      discards the logging messages.
00086 // <li> a <linkto class="StreamLogSink">StreamLogSink</linkto> which sends
00087 //      the log messages to an <src>ostream</src> (typically <src>cerr</src>)
00088 // <li> a <linkto class="TableLogSink">TableLogSink</linkto> which sends
00089 //      the messages to an AIPS++ <linkto class=Table>Table</linkto>.
00090 // </ol>
00091 //
00092 // Every <src>LogSink</src> has an attached 
00093 // <linkto class=LogFilterInterface>LogFilterInterface</linkto>
00094 // which is used to reject or pass messages.
00095 // The local and global sinks have their own filters, so they can
00096 // pass different message priorities (e.g., global <src>DEBUGGING</src> and
00097 // local <src>NORMAL</src>). Generally applications code shouldn't change the
00098 // global filter.
00099 //
00100 // </synopsis>
00101 //
00102 // <example>
00103 // <srcblock>
00104 // LogMessage logMessage(...);
00105 // LogSink logger(LogMessage::NORMAL, "logtable");   // log locally to a 'logtable'
00106 // logMessage.message("this is a message").line(__LINE__);
00107 // logger.post(logMessage);                          // local and global
00108 // </srcblock>
00109 // More complete examples are in <linkto file=Logging.h>Logging.h</linkto>.
00110 // </example>
00111 //
00112 // <h3>Advanced topics</h3>
00113 // All possible sinks are derived from an abstract base class:
00114 // <linkto class=LogSinkInterface>LogSinkInterface</linkto>. If you want to
00115 // allow for logging to a different type of sink (i.e. different from
00116 // a stream or Table) , you first need to derive a new class from
00117 // <src>LogSinkInterface</src>, and then add a new constructor to
00118 // <src>LogSink</src>.
00119 //
00120 // <src>LogSink</src> itself contains a reference to the actual object that
00121 // disposes of the messages. Several <src>LogSink</src>'s can share the same
00122 // actual sink via the copy constructor or assignment operator.
00123 // <srcblock>
00124 // LogSink logger1(LogMessage::NORMAL, "logtable");
00125 // LogSink logger2(logger1);  // logger2 references logger1
00126 // logger2.post(message);     // ends up in "logtable"
00127 // </srcblock>
00128 // You can even have different <src>LogFilterInterface</src>'s 
00129 // attached to the different <src>LogSink</src>s.
00130 //
00131 // <motivation>
00132 // Logging changes to data and informing users what the software is doing in
00133 // detail.
00134 // </motivation>
00135 //
00136 // <todo asof="1996/07/24">
00137 //   <li> More sink types - in particular to Glish.
00138 //   <li> A "tee" Sink type might be useful.
00139 // </todo>
00140 
00141 class LogSink : public LogSinkInterface
00142 {
00143 public:
00144   //#If you add more sink types, modify the <ol> in the synopsis as well.
00145   // Create a null local sink that throws all messages away or create
00146   // a memory local sink that holds the messages in memory.
00147   // If a filter isn't defined, default to <src>NORMAL</src>.
00148   // <group>
00149   explicit LogSink (LogMessage::Priority filter = LogMessage::NORMAL,
00150                     Bool nullSink = True);
00151   explicit LogSink (const LogFilterInterface &filter, Bool nullSink = True);
00152   // </group>
00153 
00154   // Log to an ostream. It is the responsiblity of the caller to ensure that
00155   // <src>os</src> will last as long as the <src>LogSink</src>s that use it.
00156   // Normally you would use <src>&cerr</src> as the argument.
00157   // <group>
00158   LogSink (LogMessage::Priority filter, ostream *os,
00159            Bool useGlobalSink = True);
00160   LogSink (const LogFilterInterface &filter, ostream *os,
00161            Bool useGlobalSink = True);
00162   // </group>
00163 
00164   // Log to the given sink.
00165   // It is primarily intended to log to a
00166   // <linkto class=TableLogSink>TableLogSink</linkto>.
00167   LogSink (const LogFilterInterface &filter,
00168            const CountedPtr<LogSinkInterface>&);
00169 
00170   // Make a referencing copy of <src>other</src>. That is, if you post a
00171   // message to the new object, it behaves as if you had posted it to the
00172   // old one (so long as their filters are the same).
00173   // <group>
00174   LogSink (const LogSink &other);
00175   LogSink &operator= (const LogSink &other);
00176   // </group>
00177 
00178   // Temporary to avoid problem that the bool constructor is taken
00179   // if a char* is passed.
00180   // They are not implemented, so compiler should give warning.
00181   // The 3rd argument is added to make it different from current
00182   // version which is still in the system library.
00183    LogSink (const LogFilterInterface &filter, const String &fileName, Int n=0);
00184    LogSink (const LogFilterInterface &filter, const Char* fileName, Int n=0);
00185    LogSink (LogMessage::Priority, const String &fileName, Int n=0);
00186    LogSink (LogMessage::Priority, const Char* fileName, Int n=0);
00187 
00188   ~LogSink();
00189 
00190   // Send <src>message</src> to both the local and global sink. Return
00191   // <src>True</src> if it passes either of them.
00192   Bool post (const LogMessage &message);
00193 
00194   // Send <src>message</src> to the global sink only. Returns <src>True</src>
00195   // if it passes the filter.
00196   static Bool postGlobally (const LogMessage &message);
00197   // Send <src>message</src> to the local sink only. Returns <src>True</src>
00198   // if it passes the filter.
00199   virtual Bool postLocally (const LogMessage &message);
00200 
00201   // Post <src>message</src> and then throw an <src>AipsError</src> exception
00202   // containing <src>message.toString()</src>. It is always posted as a 
00203   // <src>SEVERE</src> priority message, no matter what 
00204   // <src>message.priority()</src> says.
00205   // <group>
00206   template<typename EXC> void postThenThrow (const LogMessage &message,
00207                                              const EXC& exc)
00208     { preparePostThenThrow(message, exc); throw exc; }
00209   static void postGloballyThenThrow (const LogMessage &message);
00210   // </group>
00211 
00212   // Get number of messages in local sink.
00213   virtual uInt nelements() const;
00214 
00215   // Get given part of the i-th message from the local sink.
00216   // <group>
00217   virtual Double getTime (uInt i) const;
00218   virtual String getPriority (uInt i) const;
00219   virtual String getMessage (uInt i) const;
00220   virtual String getLocation (uInt i) const;
00221   virtual String getObjectID (uInt i) const;
00222   // </group>
00223 
00224   // Write a message (usually from another logsink) into the local one.
00225   // The default implementation does nothing.
00226   virtual void writeLocally (Double time, const String& message,
00227                              const String& priority, const String& location,
00228                              const String& objectID);
00229 
00230   // Clear the local sink (i.e. remove all messages from it).
00231   virtual void clearLocally();
00232 
00233   //# Bring out of LogSinkInterface only for documentation purposes
00234   // Get or set the filter of this particular <src>LogSink</src>.
00235   // <group>
00236   virtual const LogFilterInterface &filter() const;
00237   virtual LogSinkInterface &filter (const LogFilterInterface &filter);
00238   // </group>
00239 
00240   // Change the sink that this <src>LogSink</src> actually uses.
00241   // <group>
00242   const LogSinkInterface &localSink() const;
00243   LogSinkInterface &localSink();
00244   LogSink &localSink (LogSinkInterface *&fromNew);
00245   // </group>
00246 
00247   // Get/set the global sink or check if the global sink is null. The global
00248   // sink defaults to using <src>cerr</src>. Generally applications code
00249   // shouldn't change the global sink.
00250   // <group>
00251   static LogSinkInterface &globalSink();
00252   static void globalSink (LogSinkInterface *&fromNew);
00253   static Bool nullGlobalSink();
00254   // </group>
00255 
00256   // Write any pending output (by default also the global sink).
00257   virtual void flush (Bool global=True);
00258 
00259   // Returns the id for this class...
00260   static String localId( );
00261   // Returns the id of the LogSink in use...
00262   String id( ) const;
00263 
00264 private:
00265 
00266   // LsiIntermediate is a helper class to allow LogSinkInterface to implement
00267   // semantics that allow causing all classes accessing the log sink to be
00268   // aimed at a different sink object.  This used to be done by using an
00269   // odd "replace" method in CountedPtr; however, this is functionality is
00270   // being removed to CountedPtr as it is modernized so this class was
00271   // created to serve this narrow purpose.
00272 
00273   class LsiIntermediate {
00274 
00275   public:
00276 
00277 
00278       LsiIntermediate () : logSinkInterface_p (0) {}
00279       LsiIntermediate (LogSinkInterface * lsi) : logSinkInterface_p (lsi) {}
00280       ~LsiIntermediate () { delete logSinkInterface_p;}
00281 
00282       LogSinkInterface & operator* () { return * logSinkInterface_p;}
00283       LogSinkInterface * operator-> () { return logSinkInterface_p;}
00284       Bool operator! () const { return ! logSinkInterface_p;}
00285 
00286       void replace (LogSinkInterface * newLsi) { delete logSinkInterface_p; logSinkInterface_p = newLsi;}
00287 
00288   private:
00289 
00290       // Copy ctor and op= are private and not defined to prevent double-delete.
00291 
00292       LsiIntermediate (const LsiIntermediate &);
00293       LsiIntermediate & operator= (const LsiIntermediate &);
00294 
00295       LogSinkInterface * logSinkInterface_p;
00296 
00297   };
00298 
00299   // Prepare for postThenThrow function.
00300   void preparePostThenThrow(const LogMessage &message, const AipsError& x) ;
00301 
00302   // Create the global sink (attached to cerr).
00303   static void createGlobalSink();
00304 
00305   //# Data members.
00306   CountedPtr<LogSinkInterface> local_sink_p;
00307   static CountedPtr<LsiIntermediate> * global_sink_p;
00308   static Mutex theirMutex;
00309 
00310   // The following is a reference to the global sink. It is created to
00311   // ensure that the global sink is not destroyed before the last local
00312   // reference to it is destroyed. This can happen if you have a static
00313   // LogSink (or LogIO).
00314   CountedPtr<LsiIntermediate> local_ref_to_global_p;
00315   Bool useGlobalSink_p;
00316 };
00317 
00318 
00319 
00320 } //# NAMESPACE CASA - END
00321 
00322 #endif