MsgLogger/src/MsgLoggerImpl.cpp

Go to the documentation of this file.
00001 //--------------------------------------------------------------------------
00002 // File and Version Information:
00003 //      $Id: MsgLoggerImpl.cpp 8749 2014-07-30 22:19:28Z gapon@SLAC.STANFORD.EDU $
00004 //
00005 // Description:
00006 //      Class MsgLoggerImpl
00007 //
00008 // Environment:
00009 //      Software developed for the BaBar Detector at the SLAC B-Factory.
00010 //
00011 // Author List:
00012 //      Andy Salnikov
00013 //
00014 // Copyright Information:
00015 //      Copyright (C) 2005 SLAC
00016 //
00017 //------------------------------------------------------------------------
00018 
00019 //-----------------------
00020 // This Class's Header --
00021 //-----------------------
00022 #include "MsgLogger/MsgLoggerImpl.h"
00023 
00024 //-------------
00025 // C Headers --
00026 //-------------
00027 extern "C" {
00028 #include <stdlib.h>
00029 }
00030 
00031 //---------------
00032 // C++ Headers --
00033 //---------------
00034 #include <algorithm>
00035 #include <map>
00036 #include <sstream>
00037 #include <iostream>
00038 #include <boost/shared_ptr.hpp>
00039 #include <boost/thread/mutex.hpp>
00040 #if BOOST_VERSION>105200
00041 #include <boost/thread/lock_guard.hpp> 
00042 #endif
00043 
00044 //-------------------------------
00045 // Collaborating Class Headers --
00046 //-------------------------------
00047 #include "MsgLogger/MsgHandler.h"
00048 #include "MsgLogger/MsgHandlerStdStreams.h"
00049 #include "MsgLogger/MsgLogRecord.h"
00050 
00051 //-----------------------------------------------------------------------
00052 // Local Macros, Typedefs, Structures, Unions and Forward Declarations --
00053 //-----------------------------------------------------------------------
00054 
00055 namespace {
00056 
00057   // loggers
00058   typedef std::map< std::string, boost::shared_ptr<MsgLogger::MsgLoggerImpl> > Name2ImplMap ;
00059   struct Name2Impl {
00060     Name2Impl () : map(), destroyed(false) {}
00061     ~Name2Impl () { destroyed = true ; }
00062     Name2ImplMap map ;
00063     bool destroyed ;
00064   } ;
00065   Name2Impl implementations ;
00066 
00067   // find the parent logger name
00068   std::string parentName ( const std::string& name ) {
00069     std::string::size_type n = name.rfind('.') ;
00070     if ( n == std::string::npos ) {
00071       return std::string() ;
00072     } else {
00073       return std::string( name, 0, n ) ;
00074     }
00075   }
00076 
00077   // initialize root logger
00078   void initRoot ( MsgLogger::MsgLoggerImpl& root ) {
00079     root.addHandler ( new MsgLogger::MsgHandlerStdStreams ) ;
00080   }
00081 
00082   // read config stuff
00083   void readConfig() ;
00084 
00085   // mutex used to serialize creation of the loggers
00086   static boost::mutex newLoggerMutex ;
00087 
00088 }
00089 
00090 namespace MsgLogger {
00091 
00092 
00093 
00094 
00095 //              ----------------------------------------
00096 //              -- Public Function Member Definitions --
00097 //              ----------------------------------------
00098 
00099 // Construct named logger
00100 MsgLoggerImpl::MsgLoggerImpl( const std::string& name )
00101   : _name(name)
00102   , _level( MsgLogLevel::defaultLevel() )
00103   , _propagate( ! name.empty() )              // root logger does not propagate
00104   , _parent(0)
00105   , _handlers()
00106 {
00107 }
00108 
00109 // Destructor
00110 MsgLoggerImpl::~MsgLoggerImpl()
00111 {
00112   // destroy all my handlers
00113   for ( HandlerList::const_iterator it = _handlers.begin() ; it != _handlers.end() ; ++it ) {
00114     delete *it ;
00115   }
00116 }
00117 
00118 
00119 /// add a handler for the messages, takes ownership of the object
00120 void
00121 MsgLoggerImpl::addHandler ( MsgHandler* handler )
00122 {
00123   _handlers.push_back ( handler ) ;
00124 }
00125 
00126 
00127 /// check if the specified level will log any message
00128 bool
00129 MsgLoggerImpl::logging ( MsgLogLevel level ) const
00130 {
00131   // maybe it's time to initialize?
00132   if ( _name.empty() && _handlers.empty() ) {
00133     ::initRoot ( const_cast<MsgLoggerImpl&>(*this) ) ;
00134   }
00135 
00136   // if my own level is higher then don't log through my handlers
00137   if ( level >= _level ) {
00138     // if any handler can log then log
00139     for ( HandlerList::const_iterator it = _handlers.begin() ; it != _handlers.end() ; ++it ) {
00140       if ( (*it)->logging(level) ) return true ;
00141     }
00142   }
00143 
00144   // otherwise ask my parent
00145   if ( _propagate ) {
00146     if ( ! _parent ) {
00147       _parent = getLogger( ::parentName (_name) ) ;
00148       // if can't make parent then don't try to propagate
00149       if ( ! _parent ) _propagate = false ;
00150     }
00151     if ( _parent ) {
00152       return _parent->logging(level) ;
00153     }
00154   }
00155 
00156   return false ;
00157 }
00158 
00159 /// get the stream for the specified log level
00160 bool
00161 MsgLoggerImpl::log ( const MsgLogRecord& record ) const
00162 {
00163   // maybe it's time to initialize?
00164   if ( _name.empty() && _handlers.empty() ) {
00165     ::initRoot ( const_cast<MsgLoggerImpl&>(*this) ) ;
00166   }
00167 
00168   if ( record.level() >= _level ) {
00169     // send to all handlers
00170     for ( HandlerList::const_iterator it = _handlers.begin() ; it != _handlers.end() ; ++it ) {
00171       (*it)->log(record) ;
00172     }
00173   }
00174 
00175   // and send it to my parent
00176   if ( _propagate ) {
00177     if ( ! _parent ) {
00178       _parent = getLogger( ::parentName (_name) ) ;
00179       // if can't make parent then don't try to propagate
00180       if ( ! _parent ) _propagate = false ;
00181     }
00182     if ( _parent ) {
00183       _parent->log ( record ) ;
00184     }
00185   }
00186 
00187   return true ;
00188 }
00189 
00190 MsgLoggerImpl*
00191 MsgLoggerImpl::getLogger( const std::string& name )
00192 {
00193   if ( implementations.destroyed ) {
00194     return 0 ;
00195   }
00196 
00197   boost::lock_guard<boost::mutex> lock(::newLoggerMutex);
00198 
00199   // on the first call read configuration
00200   if ( implementations.map.empty() ) {
00201     try {
00202       ::readConfig() ;
00203     } catch ( const std::exception& e ) {
00204       std::cerr << "MsgLogger: Error while parsing MSGLOGCONFIG: " << e.what() << std::endl ;
00205     }
00206   }
00207 
00208   // maybe we have it already?
00209   Name2ImplMap::const_iterator it = implementations.map.find ( name ) ;
00210   if ( it != implementations.map.end() ) {
00211     return it->second.get() ;
00212   }
00213 
00214   // need to make a new one
00215   boost::shared_ptr<MsgLoggerImpl> logger ( new MsgLoggerImpl( name ) ) ;
00216   implementations.map.insert ( Name2ImplMap::value_type ( name, logger ) ) ;
00217 
00218   return logger.get() ;
00219 }
00220 
00221 
00222 } // namespace MsgLogger
00223 
00224 namespace {
00225 
00226   // make one logger
00227   void makeLogger ( const std::string& name, const std::string& level, bool propagate )
00228   {
00229     // check first
00230     Name2ImplMap::const_iterator it = implementations.map.find ( name ) ;
00231     if ( it != implementations.map.end() ) {
00232       return ;
00233     }
00234 
00235     MsgLogger::MsgLogLevel s ( level ) ;
00236 
00237     boost::shared_ptr<MsgLogger::MsgLoggerImpl> logger ( new MsgLogger::MsgLoggerImpl( name ) ) ;
00238 
00239     // do not setup handler for root logger, it will be done later in initRoot,
00240     // give user a chance to set different handlers
00241     if ( ! name.empty() ) logger->addHandler ( new MsgLogger::MsgHandlerStdStreams ) ;
00242 
00243     logger->setLevel ( s ) ;
00244     logger->propagate ( propagate ) ;
00245     implementations.map.insert ( Name2ImplMap::value_type ( name, logger ) ) ;
00246 
00247   }
00248 
00249   // read config stuff
00250   void readConfig()
00251   {
00252     const char* env = getenv ( "MSGLOGCONFIG" ) ;
00253     if ( ! env ) return ;
00254 
00255     const std::string configEnv(env) ;
00256 
00257     // configuration string will have format:
00258     // level0;logger1,logger2=level1;logger3=level2;...
00259     // if the level name is given without loggers then it
00260     // applies to root logger
00261 
00262     typedef std::string::const_iterator iter ;
00263     for ( iter i = configEnv.begin(), j ; i != configEnv.end() ; i = j ) {
00264 
00265       // find next ;
00266       j = std::find ( i, configEnv.end(), ';' ) ;
00267 
00268       // find '='
00269       iter j1 = std::find ( i, j, '=' ) ;
00270       if ( j1 == j ) {
00271         // no = means it should be a level name for root logger
00272         std::string level(i,j) ;
00273         ::makeLogger ( std::string(), level, false ) ;
00274       } else {
00275         bool propagate = *(j-1) != '-' ;
00276         std::string level( j1+1, *(j-1)=='-' ? j-1 : j ) ;
00277 
00278         for ( iter i2 = i, j2 ; i2 != j1 ; i2 = j2 ) {
00279           j2 = std::find( i2, j1, ',') ;
00280           std::string name ( i2, j2 ) ;
00281           if ( j2 != j1 ) ++ j2 ;
00282           ::makeLogger ( name, level, propagate ) ;
00283         }
00284 
00285       }
00286 
00287       // advance past semicolon
00288       if ( j != configEnv.end() ) ++ j ;
00289 
00290     }
00291 
00292   }
00293 
00294 
00295 }

Generated on 19 Dec 2016 for PSANAclasses by  doxygen 1.4.7