ISIS Core Library 0.7.2 (api 3.0.0)

/scr/tee1/isis/lib/Core/CoreUtils/message.cpp

Go to the documentation of this file.
00001 //
00002 // C++ Implementation: message
00003 //
00004 // Description:
00005 //
00006 //
00007 // Author: Enrico Reimer<reimer@cbs.mpg.de>, (C) 2008
00008 //
00009 // Copyright: See COPYING file that comes with this distribution
00010 //
00011 //
00012 
00013 #include "message.hpp"
00014 #include "common.hpp"
00015 #include <sys/types.h>
00016 
00017 #include <boost/date_time/posix_time/posix_time.hpp> //we need the to_string functions for the automatic conversion
00018 
00019 #ifndef WIN32
00020 #include <signal.h>
00021 #endif
00022 
00023 namespace isis
00024 {
00025 namespace util
00026 {
00027 namespace _internal
00028 {
00029 struct IsEqualMsg {
00030     std::string newMsg;
00031     bool operator()( const std::pair<boost::posix_time::ptime, std::string>& ms ) {return ms.second == newMsg;}
00032 };
00033 }
00034 const char *logLevelName( LogLevel level )
00035 {
00036     switch( level ) {
00037     case error:
00038         return "error";
00039     case warning:
00040         return "warning";
00041     case notice:
00042         return "notice";
00043     case info:
00044         return "info";
00045     case verbose_info:
00046         return "verbose";
00047     }
00048 
00049     return "//no_log//";
00050 }
00051 
00052 void MessageHandlerBase::stopBelow( LogLevel stop )
00053 {
00054 #ifdef WIN32
00055     LOG( Debug, error ) << "Sorry stopping is not supported on Win32";
00056     return;
00057 #endif
00058 #ifdef NDEBUG
00059     LOG( Debug, error ) << "Wont apply stopping because NDEBUG is set";
00060     return;
00061 #endif
00062     m_stop_below = stop;
00063 }
00064 
00065 bool MessageHandlerBase::requestStop( LogLevel _level )
00066 {
00067     if ( m_stop_below > _level ) {
00068 #ifdef WIN32
00069         return false;
00070 #else
00071         return kill( getpid(), SIGTSTP ) == 0;
00072 #endif
00073     } else
00074         return false;
00075 }
00076 
00077 std::string Message::strTime()const
00078 {
00079     return boost::posix_time::to_simple_string( m_timeStamp );
00080 }
00081 
00082 Message::Message( std::string object, std::string module, std::string file, int line, LogLevel level, boost::weak_ptr<MessageHandlerBase> _commitTo )
00083     : commitTo( _commitTo ),
00084       m_object( object ),
00085       m_module( module ),
00086       m_file( file ),
00087       m_timeStamp( boost::posix_time::microsec_clock::universal_time() ),
00088       m_line( line ),
00089       m_level( level )
00090 {}
00091 
00092 Message::Message( const Message &src ) //we need a custom copy-constructor, because the copy-contructor of ostringstream is private
00093     : std::ostringstream( src.str() ),
00094       commitTo( src.commitTo ),
00095       m_object( src.m_object ),
00096       m_module( src.m_module ),
00097       m_file( src.m_file ),
00098       m_subjects( src.m_subjects ),
00099       m_timeStamp( src.m_timeStamp ),
00100       m_line( src.m_line ),
00101       m_level( src.m_level )
00102 {}
00103 
00104 Message::~Message()
00105 {
00106     if ( shouldCommit() ) {
00107         commitTo.lock()->commit( *this );
00108         str( "" );
00109         clear();
00110         commitTo.lock()->requestStop( m_level );
00111     }
00112 }
00113 
00114 
00115 std::string Message::merge()const
00116 {
00117     std::string ret( str() );
00118     size_t found = std::string::npos;
00119     std::list<std::string>::const_iterator subj = m_subjects.begin();
00120 
00121     if ( ( found = ret.find( "{o}" ) ) != std::string::npos )
00122         ret.replace( found, 3, m_object );
00123 
00124     found = 0;
00125 
00126     while ( ( found = ret.find( "{s}", found ) ) != std::string::npos )
00127         ret.replace( found, 3, std::string( "\"" ) + * ( subj++ ) + "\"" );
00128 
00129     return ret;
00130 }
00131 
00132 bool Message::shouldCommit()const
00133 {
00134     if( str().empty() )
00135         return false;
00136 
00137     const boost::shared_ptr<MessageHandlerBase> buff( commitTo.lock() );
00138 
00139     if ( buff )
00140         return ( buff->m_level >= m_level );
00141     else return false;
00142 }
00143 
00144 LogLevel MessageHandlerBase::m_stop_below = error;
00145 
00146 
00147 std::ostream *DefaultMsgPrint::o = &::std::cerr;
00148 void DefaultMsgPrint::commit( const Message &mesg )
00149 {
00150     //first remove everything which is to old anyway
00151     std::list< std::pair<boost::posix_time::ptime, std::string> >::iterator begin = last.begin();
00152     static const boost::posix_time::millisec dist( max_age );
00153 
00154     while( begin != last.end() && begin->first + dist < mesg.m_timeStamp ) {
00155         begin++;
00156         last.pop_front();
00157     }
00158 
00159     const _internal::IsEqualMsg isEqual = {mesg.str()};
00160 
00161     begin = std::find_if( last.begin(), last.end(), isEqual );
00162 
00163     if( begin == last.end() ) { // its not in the list of the last xxx milliseconds - so print it
00164         *o << mesg.m_module << ":" << logLevelName( mesg.m_level );
00165 #ifndef NDEBUG //if with debug-info
00166         *o << "[" << mesg.m_file.leaf() << ":" << mesg.m_line << "] "; //print the file and the line
00167 #else
00168         *o << "[" << mesg.m_object << "] "; //print the object/method
00169 #endif //NDEBUG
00170         *o << mesg.merge(); //print the message itself
00171         *o << std::endl;
00172     } else {
00173         last.erase( begin ); // it was in the list - remove it
00174     }
00175 
00176     last.push_back( std::make_pair( mesg.m_timeStamp, mesg.str() ) ); // put new message on the top
00177 }
00178 
00179 void DefaultMsgPrint::setStream( ::std::ostream &_o )
00180 {
00181     o->flush();
00182     o = &_o;
00183 }
00184 
00185 }
00186 }