libmoost
|
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