libmoost
/home/mhx/git/github/libmoost/include/moost/logging/scoped_logger.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #ifndef MOOST_LOGGING_SCOPED_LOGGER_HPP
00029 #define MOOST_LOGGING_SCOPED_LOGGER_HPP
00030 
00031 #include <string>
00032 #include <sstream>
00033 #include <map>
00034 #include <vector>
00035 
00036 #include <boost/shared_ptr.hpp>
00037 
00038 #if defined(_MSC_VER)
00039 #pragma warning (push)
00040 #pragma warning ( disable: 4231 4251 4275 4786 )
00041 #endif
00042 
00043 #include <log4cxx/logger.h>
00044 #include <log4cxx/helpers/pool.h>
00045 #include <log4cxx/spi/loggingevent.h>
00046 #include <log4cxx/helpers/synchronized.h>
00047 #include <log4cxx/helpers/mutex.h>
00048 
00049 #include <log4cxx/helpers/resourcebundle.h>
00050 #include <log4cxx/helpers/transcoder.h>
00051 
00052 #include <log4cxx/appenderskeleton.h>
00053 
00054 #include "../logging.hpp"
00055 #include "../timer.h"
00056 
00057 namespace moost { namespace logging {
00058 
00067 class scoped_logger
00068 {
00069 private:
00070 
00071    struct sLogEntry
00072    {
00073       sLogEntry()
00074          : pLocationInfo(NULL) {}
00075 
00076       log4cxx::LevelPtr level;
00077       std::string message;
00078       log4cxx::spi::LocationInfo const* pLocationInfo;
00079    };
00080 
00081 public:
00082 
00083    scoped_logger()
00084     : m_startTime(boost::posix_time::microsec_clock::local_time())
00085    {
00086       init(std::string(), log4cxx::Level::getOff());
00087    }
00088 
00089    scoped_logger(const std::string& name)
00090     : m_startTime(boost::posix_time::microsec_clock::local_time())
00091    {
00092       init(name);
00093    }
00094 
00095    scoped_logger(const std::string& name, moost::timer::scoped_time& sc)
00096       : m_startTime(sc.get_time())
00097    {
00098       init(name);
00099    }
00100 
00101    scoped_logger(const std::string& name, moost::multi_timer::scoped_time& sc)
00102       : m_startTime(sc.get_time())
00103    {
00104       init(name);
00105    }
00106 
00107    scoped_logger(const std::string& name, const boost::posix_time::ptime& startTime)
00108       : m_startTime(startTime)
00109    {
00110       init(name);
00111    }
00112 
00113    ~scoped_logger()
00114    {
00115       try
00116       {
00117          forcedLog();
00118       }
00119       catch (...)
00120       {}
00121    }
00122 
00124    // scoped_logger custom
00125 
00129    void setTimingsHeader(const std::string& totTimingsHeader = "  Overall time: ", const std::string& subTimingsIndentation = "    -> ")
00130    {
00131       m_totTimingsHeader = totTimingsHeader;
00132       m_subTimingsIndentation = subTimingsIndentation;
00133    }
00134 
00135    void addSubTime(const std::string& header, int ms)
00136    {
00137       m_subTimes[header] += ms;
00138    }
00139 
00141 
00142    void forcedLog(const log4cxx::LevelPtr& level, const std::string& message)
00143    {
00144       updateHighestLevel(level);
00145 
00146       m_messages.push_back( sLogEntry() );
00147       sLogEntry& b = m_messages.back();
00148       b.level = level;
00149       b.message = message;
00150    }
00151 
00152    void forcedLog(const log4cxx::LevelPtr& level, const std::string& message, const log4cxx::spi::LocationInfo& location)
00153    {
00154       updateHighestLevel(level);
00155 
00156       m_messages.push_back( sLogEntry() );
00157       sLogEntry& b = m_messages.back();
00158       b.level = level;
00159       b.message = message;
00160       b.pLocationInfo = &location;
00161    }
00162 
00163    log4cxx::LevelPtr getLevel() const
00164    { return m_loggerLevel; }
00165 
00166    virtual void setLevel(const log4cxx::LevelPtr& level)
00167    { m_loggerLevel = level; }
00168 
00170 
00171    void debug(const std::string& msg, const log4cxx::spi::LocationInfo& location)
00172    {
00173       if (isDebugEnabled()) {
00174          forcedLog(log4cxx::Level::getDebug(), msg, location);
00175       }
00176    }
00177    void debug(const std::string& msg)
00178    {
00179       if (isDebugEnabled()) {
00180          forcedLog(log4cxx::Level::getDebug(), msg);
00181       }
00182    }
00183 
00184    void error(const std::string& msg, const log4cxx::spi::LocationInfo& location)
00185    {
00186       if (isErrorEnabled()) {
00187          forcedLog(log4cxx::Level::getError(), msg, location);
00188       }
00189    }
00190    void error(const std::string& msg)
00191    {
00192       if (isErrorEnabled()) {
00193          forcedLog(log4cxx::Level::getError(), msg);
00194       }
00195    }
00196 
00197    void fatal(const std::string& msg, const log4cxx::spi::LocationInfo& location)
00198    {
00199       if (isFatalEnabled()) {
00200          forcedLog(log4cxx::Level::getFatal(), msg, location);
00201       }
00202    }
00203    void fatal(const std::string& msg)
00204    {
00205       if (isFatalEnabled()) {
00206          forcedLog(log4cxx::Level::getFatal(), msg);
00207       }
00208    }
00209 
00210    void info(const std::string& msg, const log4cxx::spi::LocationInfo& location)
00211    {
00212       if (isInfoEnabled()) {
00213          forcedLog(log4cxx::Level::getInfo(), msg, location);
00214       }
00215    }
00216    void info(const std::string& msg)
00217    {
00218       if (isInfoEnabled()) {
00219          forcedLog(log4cxx::Level::getInfo(), msg);
00220       }
00221    }
00222 
00223    void log(const log4cxx::LevelPtr& level, const std::string& message,
00224             const log4cxx::spi::LocationInfo& location)
00225    {
00226       if (isEnabledFor(level)) {
00227          forcedLog(level, message, location);
00228       }
00229    }
00230    void log(const log4cxx::LevelPtr& level, const std::string& message)
00231    {
00232       if (isEnabledFor(level)) {
00233          forcedLog(level, message);
00234       }
00235    }
00236 
00237    void warn(const std::string& msg, const log4cxx::spi::LocationInfo& location)
00238    {
00239       if (isWarnEnabled()) {
00240          forcedLog(log4cxx::Level::getWarn(), msg, location);
00241       }
00242    }
00243    void warn(const std::string& msg)
00244    {
00245       if (isWarnEnabled()) {
00246          forcedLog(log4cxx::Level::getWarn(), msg);
00247       }
00248    }
00249 
00250    void trace(const std::string& msg, const log4cxx::spi::LocationInfo& location)
00251    {
00252       if (isTraceEnabled()) {
00253          forcedLog(log4cxx::Level::getTrace(), msg, location);
00254       }
00255    }
00256    void trace(const std::string& msg)
00257    {
00258       if (isTraceEnabled()) {
00259          forcedLog(log4cxx::Level::getTrace(), msg);
00260       }
00261    }
00262 
00264 
00265    void addRef() const
00266    { /*m_pLogger->addRef(); */}
00267    void releaseRef() const
00268    { /*m_pLogger->releaseRef(); */}
00269    virtual void addAppender(const log4cxx::AppenderPtr& /* newAppender */)
00270    { /*m_pLogger->addAppender(newAppender);*/ }
00271    void callAppenders(const log4cxx::spi::LoggingEventPtr& /* event */, log4cxx::helpers::Pool& /* pool */) const
00272    { /*m_pLogger->callAppenders(event, pool);*/ }
00273    void closeNestedAppenders()
00274    { /*m_pLogger->closeNestedAppenders();*/ }
00275 
00276    bool getAdditivity() const
00277    { return true; /*m_pLogger->getAdditivity();*/ }
00278    //log4cxx::AppenderList getAllAppenders() const
00279    //{ return m_pLogger->getAllAppenders(); }
00280    virtual const log4cxx::LevelPtr& getEffectiveLevel() const
00281    { return m_loggerLevel; }
00282    log4cxx::spi::LoggerRepositoryPtr getLoggerRepository() const
00283    { return log4cxx::Logger::getRootLogger()->getLoggerRepository(); }
00284    void getName(std::string& name) const
00285    { log4cxx::helpers::Transcoder::encode(m_name, name); }
00286    log4cxx::LoggerPtr getParent() const
00287    { return log4cxx::Logger::getRootLogger(); }
00288    log4cxx::helpers::ResourceBundlePtr getResourceBundle() const
00289    { return log4cxx::Logger::getRootLogger()->getResourceBundle(); }
00290 
00291    void removeAllAppenders()
00292    { log4cxx::Logger::getRootLogger()->removeAllAppenders(); }
00293    void removeAppender(const log4cxx::AppenderPtr& appender)
00294    { log4cxx::Logger::getRootLogger()->removeAppender(appender); }
00295    void setAdditivity(bool additive)
00296    { log4cxx::Logger::getRootLogger()->setAdditivity(additive); }
00297    inline void setResourceBundle(const log4cxx::helpers::ResourceBundlePtr& bundle)
00298    { log4cxx::Logger::getRootLogger()->setResourceBundle(bundle); }
00299    inline const log4cxx::helpers::Mutex& getMutex() const
00300    { return log4cxx::Logger::getRootLogger()->getMutex(); }
00301 
00303    // forwarded methods
00304 
00305    bool isAttached(const log4cxx::AppenderPtr& appender) const
00306    { return log4cxx::Logger::getRootLogger()->isAttached(appender); }
00307    bool isEnabledFor(const log4cxx::LevelPtr& level) const
00308    { return level->isGreaterOrEqual(m_loggerLevel); }
00309 
00310    bool isDebugEnabled() const
00311    { return m_loggerLevel->toInt() <= log4cxx::Level::DEBUG_INT; }
00312    bool isInfoEnabled() const
00313    { return m_loggerLevel->toInt() <= log4cxx::Level::INFO_INT; }
00314    bool isWarnEnabled() const
00315    { return m_loggerLevel->toInt() <= log4cxx::Level::WARN_INT; }
00316    bool isErrorEnabled() const
00317    { return m_loggerLevel->toInt() <= log4cxx::Level::ERROR_INT; }
00318    bool isFatalEnabled() const
00319    { return m_loggerLevel->toInt() <= log4cxx::Level::FATAL_INT; }
00320    bool isTraceEnabled() const
00321    { return m_loggerLevel->toInt() <= log4cxx::Level::TRACE_INT; }
00322 
00325 
00326    //AppenderPtr getAppender(const LogString& name) const;
00327 
00328    //void forcedLogLS( const LevelPtr& level, const log4cxx::LogString& message,
00329    //                  const log4cxx::spi::LocationInfo& location) const;
00330    // static LoggerPtr getLoggerLS(const LogString& name);
00331    //static LoggerPtr getLoggerLS(const LogString& name,
00332    //                             const log4cxx::spi::LoggerFactoryPtr& factory);
00333    //void removeAppender(const LogString& name)
00334    //void l7dlog(const LevelPtr& level, const LogString& key,
00335    //            const log4cxx::spi::LocationInfo& locationInfo,
00336    //            const std::vector<LogString>& values) const;
00337    //void logLS(const LevelPtr& level, const LogString& message,
00338    //           const log4cxx::spi::LocationInfo& location) const;
00339    //const LogString getName() const { return name; }
00340 
00341 private:
00342 
00343    void forcedLog()
00344    {
00345       if ( !m_highestMessageLevel )
00346          m_highestMessageLevel = m_loggerLevel;
00347 
00348       if ( isTraceEnabled() )
00349       {
00350          std::ostringstream buf;
00351          buf << "\n";
00352 
00353          // get subtimes
00354          if ( !m_subTimes.empty() )
00355          {
00356             std::map<std::string, int>::const_iterator it;
00357             for ( it = m_subTimes.begin(); it != m_subTimes.end(); ++it )
00358                buf << ">>> " << m_subTimingsIndentation << it->first << ": " <<  it->second << "ms\n";
00359 
00360          }
00361 
00362          // get overall time
00363          int timeMs  = static_cast<int> (
00364             (  boost::posix_time::microsec_clock::local_time() -
00365             m_startTime
00366             ).total_milliseconds() );
00367 
00368          buf << "   " << m_totTimingsHeader << timeMs << "ms\n";
00369 
00370          m_messages.push_back( sLogEntry() );
00371          sLogEntry& b = m_messages.back();
00372          b.level = log4cxx::Level::getDebug();
00373          b.message = buf.str();
00374       }
00375 
00376       std::vector< std::pair<log4cxx::LevelPtr, log4cxx::AppenderPtr> >::iterator aIt;
00377       std::vector<sLogEntry>::const_iterator mIt;
00378 
00379       std::string message;
00380       log4cxx::helpers::Pool p;
00381       log4cxx::LogString msg;
00382 
00383       for ( aIt = m_appenders.begin(); aIt != m_appenders.end(); ++aIt )
00384       {
00385          const log4cxx::LevelPtr& appenderLevel = aIt->first;
00386          log4cxx::AppenderPtr& appender = aIt->second;
00387 
00388          std::ostringstream buf;
00389          log4cxx::spi::LocationInfo const* pLocationInfo = NULL;
00390 
00391          if(!m_messages.empty())
00392          {
00393             buf << "\n";
00394 
00395             for ( mIt = m_messages.begin(); mIt != m_messages.end(); ++mIt )
00396             {
00397                if ( mIt->level->isGreaterOrEqual( appenderLevel ) )
00398                {
00399                   buf << "   " << mIt->message << "\n";
00400                   pLocationInfo = mIt->pLocationInfo;
00401                }
00402             }
00403          }
00404 
00405          message = buf.str();
00406          if ( message.empty() )
00407             continue;
00408 
00409          LOG4CXX_DECODE_CHAR(msg, message);
00410 
00411          if ( pLocationInfo )
00412          {
00413             log4cxx::spi::LoggingEventPtr event(new log4cxx::spi::LoggingEvent( m_name, m_highestMessageLevel, msg,
00414                *pLocationInfo ));
00415             appender->doAppend(event, p);
00416          }
00417          else
00418          {
00419             log4cxx::spi::LoggingEventPtr event(new log4cxx::spi::LoggingEvent( m_name, m_highestMessageLevel, msg,
00420                log4cxx::spi::LocationInfo::getLocationUnavailable()));
00421             appender->doAppend(event, p);
00422          }
00423 
00424       }
00425    }
00426 
00427    void updateHighestLevel(const log4cxx::LevelPtr& level)
00428    {
00429       if ( !m_highestMessageLevel || // no level was set
00430          ( !level->equals(m_highestMessageLevel) && level->isGreaterOrEqual(m_highestMessageLevel) ) // it's a higher level!
00431          )
00432       {
00433          m_highestMessageLevel = level;
00434       }
00435    }
00436 
00437 public:
00443    void init(const std::string& name, log4cxx::LevelPtr level = log4cxx::Level::getFatal())
00444    {
00445       setTimingsHeader();
00446       log4cxx::helpers::Transcoder::decode(name, m_name);
00447 
00448       log4cxx::LoggerPtr pRoot = log4cxx::Logger::getRootLogger();
00449       m_loggerLevel = level;
00450 
00451       //const log4cxx::helpers::Mutex& mutex = pRoot->getMutex();
00452       //log4cxx::helpers::synchronized s(mutex);
00453 
00454       // go through the list of appenders and set the lowest threshold!
00455       log4cxx::AppenderList al = pRoot->getAllAppenders();
00456       log4cxx::AppenderList::const_iterator it;
00457       for ( it = al.begin(); it != al.end(); ++it )
00458       {
00459          // Looks ugly, but works quite nicely (TM)
00460          // The static_cast<> invokes the overloaded cast operator of the ObjectPtrT<> template and turns
00461          // the AppenderPtr into and Appender *, which we can easily downcast to an AppenderSkeleton *.
00462          log4cxx::AppenderSkeleton *pSkeletonAppender = dynamic_cast<log4cxx::AppenderSkeleton*>(static_cast<log4cxx::Appender *>(*it));
00463          if ( !pSkeletonAppender )
00464             continue;
00465 
00466          const log4cxx::LevelPtr& pLvl = pSkeletonAppender->getThreshold();
00467 
00468          if ( !pLvl )
00469             continue;
00470 
00471          m_appenders.push_back( std::make_pair(pLvl, *it) );
00472 
00473          if ( m_loggerLevel->isGreaterOrEqual(pLvl) )
00474          {
00475             m_loggerLevel = pLvl;
00476          }
00477       }
00478    }
00479 
00480 private:
00481 
00487    log4cxx::LevelPtr m_loggerLevel;
00488 
00493    log4cxx::LevelPtr m_highestMessageLevel;
00494 
00498    log4cxx::LogString m_name;
00499 
00503    std::vector<sLogEntry> m_messages;
00504 
00508    std::vector< std::pair<log4cxx::LevelPtr, log4cxx::AppenderPtr> > m_appenders;
00509 
00510    boost::posix_time::ptime m_startTime;
00511    std::map<std::string, int> m_subTimes;
00512 
00513    std::string m_totTimingsHeader;
00514    std::string m_subTimingsIndentation;
00515 };
00516 
00517 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
00518 
00519 typedef boost::shared_ptr<moost::logging::scoped_logger> LoggerPtr;
00520 
00521 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
00522 
00523 class scoped_timing
00524 {
00525 public:
00526    scoped_timing( LoggerPtr& logger, const std::string& str)
00527       : m_pLogger(logger), m_str(str),
00528         m_startTime(boost::posix_time::microsec_clock::local_time())
00529    {}
00530 
00531    ~scoped_timing()
00532    {
00533       try
00534       {
00535          int timeMs  = static_cast<int> (
00536             (  boost::posix_time::microsec_clock::local_time() -
00537                m_startTime
00538             ).total_milliseconds() );
00539 
00540          m_pLogger->addSubTime( m_str, timeMs);
00541       }
00542       catch (...)
00543       {}
00544    }
00545 
00546 private:
00547 
00548    LoggerPtr& m_pLogger;
00549    std::string m_str;
00550    boost::posix_time::ptime m_startTime;
00551 };
00552 
00553 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
00554 
00555 #define MLOG_SCOPED_NAMED_DEFINE(logger, name) \
00556    moost::logging::LoggerPtr logger( new moost::logging::scoped_logger( name ) )
00557 
00558 #define MLOG_SCOPED_FUNC_DEFINE(logger) \
00559    moost::logging::LoggerPtr logger( new moost::logging::scoped_logger( MLOG_FUNC_NAME() ) )
00560 
00561 #define MLOG_SCOPED_NAMED_TIME_DEFINE(logger, name, time) \
00562    moost::logging::LoggerPtr logger( new moost::logging::scoped_logger( name, time ) )
00563 
00564 #define MLOG_SCOPED_FUNC_TIME_DEFINE(logger, time) \
00565    moost::logging::LoggerPtr logger( new moost::logging::scoped_logger( MLOG_FUNC_NAME(), time ) )
00566 
00572 #define MLOG_SCOPED_FM303_DEFINE(logger, name) \
00573    moost::multi_timer::scoped_time st(fm303_multi_timer(), name); \
00574    MLOG_SCOPED_NAMED_TIME_DEFINE(logger, name, st)
00575 
00581 #define MLOG_SCOPED_FM303_FUNCTION_DEFINE(logger) \
00582    moost::multi_timer::scoped_time st(fm303_multi_timer(), MLOG_FUNC_NAME()); \
00583    MLOG_SCOPED_NAMED_TIME_DEFINE(logger, MLOG_FUNC_NAME(), st)
00584 
00591 #define MLOG_SCOPED_FM303_CLASS_DEFINE(logger) \
00592    moost::multi_timer::scoped_time st(fm303_multi_timer(), typeid(*this).name()); \
00593    MLOG_SCOPED_NAMED_TIME_DEFINE(logger, typeid(*this).name(), st)
00594 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
00595 
00596 #if defined(_MSC_VER)
00597 #pragma warning ( pop )
00598 #endif
00599 
00600 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
00601 
00602 }}
00603 
00604 #endif // #define MOOST_LOGGING_SCOPED_LOGGER_HPP