libmoost
/home/mhx/git/github/libmoost/include/moost/scoped_verbose.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #ifndef MOOST_SCOPED_VERBOSE_H
00029 #define MOOST_SCOPED_VERBOSE_H
00030 
00031 #include <sstream>
00032 #include <iostream>
00033 #include <cassert>
00034 
00035 #include "timer.h"
00036 #include "terminal_format.hpp"
00037 
00038 #include <boost/shared_ptr.hpp>
00039 #include <boost/date_time/posix_time/posix_time.hpp> // timing
00040 
00041 #define MOOST_SCOPED_VERBOSE_BOOKMARK_SEP "__scoped__"
00042 #define MOOST_RECURRING_VERBOSE_BOOKMARK_SEP "__recurring__"
00043 
00044 // forward declaration
00045 namespace moost
00046 {
00047    class scoped_verbose;
00048 }
00049 
00050 // declaration overriding
00051 namespace std
00052 {
00053    // free functions
00054    inline moost::scoped_verbose& endl(moost::scoped_verbose& sv);
00055    // free functions
00056    inline moost::scoped_verbose& flush(moost::scoped_verbose& sv);
00057 }
00058 
00059 namespace moost {
00060 
00159 class scoped_verbose
00160 {
00161 public:
00162 
00163    enum eVerboseLevel
00164    {
00165       VL_HIGH_PRIORITY,
00166       VL_WARNING_PRIORITY,
00167       VL_LOW_PRIORITY,
00168       VL_EVERYTHING,
00169       VL_MAX = VL_EVERYTHING
00170    };
00171 
00172    class scoped_bookmark
00173    {
00174    public:
00175       scoped_bookmark(scoped_verbose& sv, const std::string& str)
00176          : m_sv(sv), m_str(str)
00177       {
00178          m_sv.addBookmark(MOOST_SCOPED_VERBOSE_BOOKMARK_SEP);
00179       }
00180 
00181       ~scoped_bookmark()
00182       {
00183          m_sv.addBookmark(m_str);
00184       }
00185 
00186    private:
00187       scoped_verbose& m_sv;
00188       std::string m_str;
00189    };
00190 
00191    class recurrurring_bookmark
00192    {
00193    public:
00194       recurrurring_bookmark(scoped_verbose& sv, const std::string& str)
00195          : m_sv(sv), m_str(str)
00196       {
00197          m_sv.addBookmark(MOOST_RECURRING_VERBOSE_BOOKMARK_SEP);
00198       }
00199 
00200       ~recurrurring_bookmark()
00201       {
00202          m_sv.addBookmark(m_str);
00203       }
00204 
00205    private:
00206       scoped_verbose& m_sv;
00207       std::string m_str;
00208    };
00209 
00210 
00211 public:
00212 
00213    scoped_verbose(const std::string& header, eVerboseLevel vl = VL_WARNING_PRIORITY, std::ostream& out = std::cout)
00214       : m_header(header), m_vl(vl), m_out(out), m_startTime(boost::posix_time::microsec_clock::local_time()),
00215         m_currLevel(vl)
00216    { setTimingsHeader(); }
00217 
00218    scoped_verbose(const std::string& header, moost::timer::scoped_time& sc, eVerboseLevel vl = VL_WARNING_PRIORITY, std::ostream& out = std::cout)
00219       : m_header(header), m_vl(vl), m_out(out), m_startTime(sc.get_time()), m_currLevel(vl)
00220    { setTimingsHeader(); }
00221 
00222    scoped_verbose(const std::string& header, moost::multi_timer::scoped_time& sc, eVerboseLevel vl = VL_WARNING_PRIORITY, std::ostream& out = std::cout)
00223       : m_header(header), m_vl(vl), m_out(out), m_startTime(sc.get_time()), m_currLevel(vl)
00224    { setTimingsHeader(); }
00225 
00226    scoped_verbose(const std::string& header, const boost::posix_time::ptime& time, eVerboseLevel vl = VL_WARNING_PRIORITY, std::ostream& out = std::cout)
00227       : m_header(header), m_vl(vl), m_out(out), m_startTime(time), m_currLevel(vl)
00228    { setTimingsHeader(); }
00229 
00233    ~scoped_verbose()
00234    {
00235       try
00236       {
00237 
00238          std::ostringstream concatenatedBuf;
00239          if ( !m_entries.empty() )
00240          {
00241             std::vector< std::pair<eVerboseLevel, std::string> >::const_iterator eIt;
00242             for ( eIt = m_entries.begin(); eIt != m_entries.end(); ++eIt )
00243             {
00244                if ( eIt->first <= m_vl )
00245                   concatenatedBuf << eIt->second;
00246             }
00247          }
00248 
00249          if ( m_currLevel <= m_vl )
00250             concatenatedBuf << m_buf.str();
00251 
00252          long pos = static_cast<long>(concatenatedBuf.tellp());
00253          if ( pos <= 0 && m_vl != VL_EVERYTHING )
00254             return; // nothing to output
00255 
00256          using namespace boost::posix_time;
00257          std::ostringstream oss;
00258          const time_duration& td = m_startTime.time_of_day();
00259          char fill_char = '0';
00260          oss << '['
00261             << boost::gregorian::to_simple_string_type<char>(m_startTime.date()) << ' '
00262             << std::setw(2) << std::setfill(fill_char)
00263             << boost::date_time::absolute_value(td.hours()) << ":"
00264             << std::setw(2) << std::setfill(fill_char)
00265             << boost::date_time::absolute_value(td.minutes()) << ":"
00266             << std::setw(2) << std::setfill(fill_char)
00267             << boost::date_time::absolute_value(td.seconds())
00268             << '|' << m_header << "] "
00269             << concatenatedBuf.str();
00270 
00271          if ( m_vl == VL_EVERYTHING )
00272          {
00273             std::vector< std::pair<ptime, std::string> >::const_iterator tIt;
00274             std::map<std::string, std::pair<double, int> > recurringMaps;
00275 
00276             ptime lastTime = m_startTime;
00277             oss << '\n';
00278 
00279             std::string scopedSep(MOOST_SCOPED_VERBOSE_BOOKMARK_SEP);
00280             std::string recurringSep(MOOST_RECURRING_VERBOSE_BOOKMARK_SEP);
00281 
00282             for ( tIt = m_timeBookmarks.begin(); tIt != m_timeBookmarks.end(); ++tIt )
00283             {
00284                if ( tIt->second == recurringSep )
00285                {
00286                   // that's a recurring bookmark: add the difference to the map
00287                   // we will print it at theend
00288                   lastTime = tIt->first;
00289                   ++tIt;
00290                   if ( tIt == m_timeBookmarks.end() )
00291                   {
00292                      assert(!"Somehow we have only one bit of a recurring verbose!");
00293                      break; // should never happen
00294                   }
00295 
00296                   std::pair<double, int>& recurringEntry = recurringMaps[tIt->second];
00297                   recurringEntry.first += (tIt->first - lastTime).total_milliseconds();
00298                   ++recurringEntry.second;
00299                }
00300                else if ( tIt->second != scopedSep ) // if it's not a bookmark separator
00301                {
00302                   // standard entry (or the previous was bookmark)
00303                   oss << m_subTimingsIndentation << tIt->second << ": " << (tIt->first - lastTime).total_milliseconds() << "ms\n";
00304                }
00305 
00306                lastTime = tIt->first;
00307             }
00308 
00309             if ( !recurringMaps.empty() )
00310             {
00311                std::map<std::string, std::pair<double, int> >::const_iterator rmIt;
00312                for ( rmIt = recurringMaps.begin(); rmIt != recurringMaps.end(); ++rmIt )
00313                {
00314                   const std::pair<double, int>& recurringEntry = rmIt->second;
00315                   oss << m_subTimingsIndentation << rmIt->first << ": " << static_cast<int>( recurringEntry.first / recurringEntry.second + 0.5) << "ms\n";
00316                }
00317 
00318             }
00319 
00320             ptime now = microsec_clock::local_time();
00321             oss << m_totTimingsHeader << (now - m_startTime).total_milliseconds() << "ms";
00322          }
00323 
00324          oss << '\n';
00325          m_out << oss.str() << std::flush;
00326       }
00327       catch (...)
00328       { }
00329    }
00330 
00337    template <typename T>
00338    void addError(const T& str, bool addErrorHeader = false, bool addNewLine = true)
00339    {
00340       if ( addNewLine )
00341          addToStream('\n', VL_HIGH_PRIORITY);
00342       if ( addErrorHeader )
00343          addToStream(moost::terminal_format::getError() + ": ", VL_HIGH_PRIORITY);
00344 
00345       addToStream(str, VL_HIGH_PRIORITY);
00346    }
00347 
00355    template <typename T>
00356    void addWarning(const T& str, bool addWarningHeader = false, bool addNewLine = true)
00357    {
00358       if ( m_vl >= VL_WARNING_PRIORITY )
00359       {
00360          if ( addNewLine )
00361             addToStream('\n', VL_WARNING_PRIORITY);
00362          if ( addWarningHeader )
00363             addToStream(moost::terminal_format::getWarning() + ": ", VL_WARNING_PRIORITY);
00364 
00365          addToStream(str, VL_WARNING_PRIORITY);
00366       }
00367    }
00368 
00374    template <typename T>
00375    scoped_verbose& operator<<(const T& str)
00376    {
00377       if ( m_vl >= VL_LOW_PRIORITY )
00378          addToStream(str, VL_LOW_PRIORITY);
00379       return *(this);
00380    }
00381 
00382    template <typename T>
00383    void addTrivial(const T& str)
00384    {
00385       if ( m_vl >= VL_EVERYTHING )
00386          addToStream(str, VL_EVERYTHING);
00387    }
00388 
00389    template <typename T>
00390    void add(const T& str, eVerboseLevel lvl)
00391    {
00392       if ( m_vl >= lvl )
00393          addToStream(str, VL_LOW_PRIORITY);
00394    }
00395 
00396    scoped_verbose& flush()
00397    { return *this; } // do nothing
00398 
00399    scoped_verbose & operator << (scoped_verbose & (*modifier)(scoped_verbose &))
00400    { modifier(*this); return *this; };
00401 
00406    void setHeader(const std::string& header)
00407    { m_header = header; }
00408 
00413    static std::string stringize(eVerboseLevel lvl)
00414    {
00415       switch (lvl)
00416       {
00417       case VL_LOW_PRIORITY:
00418          return "LOW PRIORITY";
00419       case VL_WARNING_PRIORITY:
00420          return "WARNING PRIORITY";
00421       case VL_HIGH_PRIORITY:
00422          return "HIGH PRIORITY";
00423       case VL_EVERYTHING:
00424          return "EVERYTHING";
00425       }
00426       return "UNKNOWN";
00427    }
00428 
00432    std::string stringize()
00433    {
00434       return stringize(m_vl);
00435    }
00436 
00466    void addBookmark(const std::string& str )
00467    {
00468       if ( m_vl < VL_EVERYTHING )
00469          return; // ignore unless we're verbosing everything!
00470 
00471       m_timeBookmarks.push_back(
00472          make_pair( boost::posix_time::microsec_clock::local_time(),
00473                     str ) )
00474       ;
00475    }
00476 
00481    void changeVerboseLevel(eVerboseLevel vl = VL_EVERYTHING)
00482    { m_vl = vl; }
00483 
00487    eVerboseLevel getVerboseLevel() const
00488    { return m_vl; }
00489 
00490    void setTimingsHeader(const std::string& totTimingsHeader = "  Overall time: ", const std::string& subTimingsIndentation = "    -> ")
00491    {
00492       m_totTimingsHeader = totTimingsHeader;
00493       m_subTimingsIndentation = subTimingsIndentation;
00494    }
00495 
00496 protected:
00497 
00498    template <typename T>
00499    void addToStream(const T& str, eVerboseLevel toLevel)
00500    {
00501       if ( toLevel != m_currLevel )
00502       {
00503          m_entries.push_back( make_pair(m_currLevel, m_buf.str()) );
00504 
00505          m_buf.str(""); // reset
00506          m_currLevel = toLevel;
00507       }
00508 
00509       m_buf << str;
00510       //*((std::ostringstream*)this) << str;
00511    }
00512 
00513    std::string   m_header; //< header of the message
00514 
00515    eVerboseLevel m_vl; //< the verbose level
00516    std::ostream& m_out; //< where it will be eventually output
00517 
00518    std::ostringstream m_buf;
00519 
00520    std::vector< std::pair<eVerboseLevel, std::string> > m_entries;
00521 
00522    boost::posix_time::ptime m_startTime; //< when it started
00523 
00524    std::string m_totTimingsHeader; //< the indentation string used while output the total timing
00525    std::string m_subTimingsIndentation; //< the indentation string used while output bookmarked timings
00526 
00527    std::vector< std::pair<boost::posix_time::ptime, std::string> > m_timeBookmarks; //< the time bookmarks
00528 
00529    eVerboseLevel m_currLevel;
00530 };
00531 
00532 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
00533 
00534 #define LEVEL_SCOPED_VERBOSE( level, lvl_enum )         \
00535 class level##_scoped_verbose                            \
00536 {                                                       \
00537 public:                                                 \
00538    level##_scoped_verbose(scoped_verbose& sv)           \
00539    : m_sv(sv) {}                                        \
00540                                                         \
00541    template <typename T>                                \
00542    level##_scoped_verbose& operator<<(const T& str)     \
00543    {                                                    \
00544       m_sv.add(str, lvl_enum);                          \
00545       return *(this);                                   \
00546    }                                                    \
00547                                                         \
00548 private:                                                \
00549                                                         \
00550    scoped_verbose& m_sv;                                \
00551 };
00552 
00553 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
00554 
00555 LEVEL_SCOPED_VERBOSE( error, scoped_verbose::VL_HIGH_PRIORITY )
00556 LEVEL_SCOPED_VERBOSE( warning, scoped_verbose::VL_WARNING_PRIORITY )
00557 LEVEL_SCOPED_VERBOSE( trivial, scoped_verbose::VL_EVERYTHING )
00558 
00559 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
00560 
00561 }
00562 
00563 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
00564 
00565 // implementation of the free functions
00566 namespace std
00567 {
00568    // free functions
00569    moost::scoped_verbose& endl(moost::scoped_verbose& sv)
00570    { return sv << '\n'; } // no flush
00571 
00572    // free functions
00573    moost::scoped_verbose& flush(moost::scoped_verbose& sv)
00574    { return sv; } // do nothing
00575 }
00576 
00577 
00578 #endif // #define MOOST_SCOPED_VERBOSE_H