//# LogSink.h: Distribute LogMessages to their destination(s) //# Copyright (C) 1996,2000,2001,2003,2016 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; if not, write to the Free Software Foundation, //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# //# $Id$ #ifndef CASA_LOGSINK_H #define CASA_LOGSINK_H #include #include #include #include #include #include namespace casacore { //# NAMESPACE CASACORE - BEGIN // // Distribute LogMessages to their destination(s) // // // // // //
  • LogMessage //
  • LogSinkInterface, if you are // interested in extending the set of destinations a LogMessage can // be sent. // // // // Log as in "Log Book." Sink from its common usage ("source/sink") as a thing // which can accept some substance or energy. // // // // The LogSink class supplies the destination for // LogMessages. There are two destinations // available through the LogSink //
      //
    1. A global destination, which is shared by all LogSinks. The global // destination will typically be a GUI window or standard output. //
    2. A local destination which is intended to log changes to // particular dataset(s). The local destination will typically be a // Casacore Table, but there is also // a local sink for temporary storage in memory. //
    // Normally the post() member function will be called which // sends the message to both the global and local destinations, however one or // the other may be chosen via LogSink::postGlobally() and // postLocally() member functions. // // The global sink will normally be set by system library code (it defaults to // using cerr. The type of local sink is defined at // construction time. Presently you can choose one of: //
      //
    1. a NullLogSink which merely // discards the logging messages. //
    2. a StreamLogSink which sends // the log messages to an ostream (typically cerr) //
    3. a TableLogSink which sends // the messages to a Casacore Table. //
    // // Every LogSink has an attached // LogFilterInterface // which is used to reject or pass messages. // The local and global sinks have their own filters, so they can // pass different message priorities (e.g., global DEBUGGING and // local NORMAL). Generally applications code shouldn't change the // global filter. // //
    // // // // LogMessage logMessage(...); // LogSink logger(LogMessage::NORMAL, "logtable"); // log locally to a 'logtable' // logMessage.message("this is a message").line(__LINE__); // logger.post(logMessage); // local and global // // More complete examples are in Logging.h. // // //

    Advanced topics

    // All possible sinks are derived from an abstract base class: // LogSinkInterface. If you want to // allow for logging to a different type of sink (i.e. different from // a stream or Table) , you first need to derive a new class from // LogSinkInterface, and then add a new constructor to // LogSink. // // LogSink itself contains a reference to the actual object that // disposes of the messages. Several LogSink's can share the same // actual sink via the copy constructor or assignment operator. // // LogSink logger1(LogMessage::NORMAL, "logtable"); // LogSink logger2(logger1); // logger2 references logger1 // logger2.post(message); // ends up in "logtable" // // You can even have different LogFilterInterface's // attached to the different LogSinks. // // // Logging changes to data and informing users what the software is doing in // detail. // // // //
  • More sink types - in particular to Glish. //
  • A "tee" Sink type might be useful. // class LogSink : public LogSinkInterface { public: //#If you add more sink types, modify the
      in the synopsis as well. // Create a null local sink that throws all messages away or create // a memory local sink that holds the messages in memory. // If a filter isn't defined, default to NORMAL. // explicit LogSink (LogMessage::Priority filter = LogMessage::NORMAL, Bool nullSink = True); explicit LogSink (const LogFilterInterface &filter, Bool nullSink = True); // // Log to an ostream. It is the responsiblity of the caller to ensure that // os will last as long as the LogSinks that use it. // Normally you would use &cerr as the argument. // LogSink (LogMessage::Priority filter, ostream *os, Bool useGlobalSink = True); LogSink (const LogFilterInterface &filter, ostream *os, Bool useGlobalSink = True); // // Log to the given sink. // It is primarily intended to log to a // TableLogSink. LogSink (const LogFilterInterface &filter, const CountedPtr&); // Make a referencing copy of other. That is, if you post a // message to the new object, it behaves as if you had posted it to the // old one (so long as their filters are the same). // LogSink (const LogSink &other); LogSink &operator= (const LogSink &other); // // Temporary to avoid problem that the bool constructor is taken // if a char* is passed. // They are not implemented, so compiler should give warning. // The 3rd argument is added to make it different from current // version which is still in the system library. LogSink (const LogFilterInterface &filter, const String &fileName, Int n=0); LogSink (const LogFilterInterface &filter, const Char* fileName, Int n=0); LogSink (LogMessage::Priority, const String &fileName, Int n=0); LogSink (LogMessage::Priority, const Char* fileName, Int n=0); ~LogSink(); // Send message to both the local and global sink. Return // True if it passes either of them. Bool post (const LogMessage &message); // Send message to the global sink only. Returns True // if it passes the filter. static Bool postGlobally (const LogMessage &message); // Send message to the local sink only. Returns True // if it passes the filter. virtual Bool postLocally (const LogMessage &message); // Post message and then throw an AipsError exception // containing message.toString(). It is always posted as a // SEVERE priority message, no matter what // message.priority() says. // template void postThenThrow (const LogMessage &message, const EXC& exc) { preparePostThenThrow(message, exc); throw exc; } static void postGloballyThenThrow (const LogMessage &message); // // Get number of messages in local sink. virtual uInt nelements() const; // Get given part of the i-th message from the local sink. // virtual Double getTime (uInt i) const; virtual String getPriority (uInt i) const; virtual String getMessage (uInt i) const; virtual String getLocation (uInt i) const; virtual String getObjectID (uInt i) const; // // Write a message (usually from another logsink) into the local one. // The default implementation does nothing. virtual void writeLocally (Double time, const String& message, const String& priority, const String& location, const String& objectID); // Clear the local sink (i.e. remove all messages from it). virtual void clearLocally(); //# Bring out of LogSinkInterface only for documentation purposes // Get or set the filter of this particular LogSink. // virtual const LogFilterInterface &filter() const; virtual LogSinkInterface &filter (const LogFilterInterface &filter); // // Change the sink that this LogSink actually uses. // const LogSinkInterface &localSink() const; LogSinkInterface &localSink(); LogSink &localSink (LogSinkInterface *&fromNew); // // Get/set the global sink or check if the global sink is null. The global // sink defaults to using cerr. Generally applications code // shouldn't change the global sink. More so, calling globalSink(fromNew) // while using the global sink is not thread-safe. And fromNew is set to 0. // static LogSinkInterface &globalSink(); static void globalSink (LogSinkInterface *&fromNew); static Bool nullGlobalSink(); // // Write any pending output (by default also the global sink). virtual void flush (Bool global=True); // Returns the id for this class... static String localId( ); // Returns the id of the LogSink in use... String id( ) const; private: // LsiIntermediate is a helper class to allow LogSinkInterface to implement // semantics that allow causing all classes accessing the log sink to be // aimed at a different sink object. This used to be done by using an // odd "replace" method in CountedPtr; however, this is functionality is // being removed to CountedPtr as it is modernized so this class was // created to serve this narrow purpose. class LsiIntermediate { public: LsiIntermediate () : logSinkInterface_p (0) {} LsiIntermediate (LogSinkInterface * lsi) : logSinkInterface_p (lsi) {} ~LsiIntermediate () { delete logSinkInterface_p;} LogSinkInterface & operator* () { return * logSinkInterface_p;} LogSinkInterface * operator-> () { return logSinkInterface_p;} Bool operator! () const { return ! logSinkInterface_p;} void replace (LogSinkInterface * newLsi) { delete logSinkInterface_p; logSinkInterface_p = newLsi;} private: // Copy ctor and op= are private and not defined to prevent double-delete. LsiIntermediate (const LsiIntermediate &); LsiIntermediate & operator= (const LsiIntermediate &); LogSinkInterface * logSinkInterface_p; }; // Prepare for postThenThrow function. void preparePostThenThrow(const LogMessage &message, const AipsError& x) ; // Create the global sink (attached to cerr). Always called using theirCallOnce. static void createGlobalSink(); //# Data members. CountedPtr local_sink_p; static CountedPtr * global_sink_p; static std::once_flag theirCallOnceFlag; // The following is a reference to the global sink. It is created to // ensure that the global sink is not destroyed before the last local // reference to it is destroyed. This can happen if you have a static // LogSink (or LogIO). CountedPtr local_ref_to_global_p; Bool useGlobalSink_p; }; } //# NAMESPACE CASACORE - END #endif