|
NCBI C++ ToolKit
|
00001 #ifndef CORELIB___PERF_LOG__HPP 00002 #define CORELIB___PERF_LOG__HPP 00003 00004 /* $Id: perf_log.hpp 52765 2012-01-25 19:08:52Z grichenk $ 00005 * =========================================================================== 00006 * 00007 * PUBLIC DOMAIN NOTICE 00008 * National Center for Biotechnology Information 00009 * 00010 * This software/database is a "United States Government Work" under the 00011 * terms of the United States Copyright Act. It was written as part of 00012 * the author's official duties as a United States Government employee and 00013 * thus cannot be copyrighted. This software/database is freely available 00014 * to the public for use. The National Library of Medicine and the U.S. 00015 * Government have not placed any restriction on its use or reproduction. 00016 * 00017 * Although all reasonable efforts have been taken to ensure the accuracy 00018 * and reliability of the software and data, the NLM and the U.S. 00019 * Government do not and cannot warrant the performance or results that 00020 * may be obtained by using this software or data. The NLM and the U.S. 00021 * Government disclaim all warranties, express or implied, including 00022 * warranties of performance, merchantability or fitness for any particular 00023 * purpose. 00024 * 00025 * Please cite the author in any work or product based on this material. 00026 * 00027 * =========================================================================== 00028 * 00029 * Author: Denis Vakatov, Vladimir Ivanov 00030 * 00031 * 00032 */ 00033 00034 /// @file perf_log.hpp 00035 /// 00036 /// Defines NCBI C++ API for timing-and-logging, classes, and macros. 00037 /// 00038 00039 #include <corelib/ncbitime.hpp> 00040 #include <corelib/ncbidiag.hpp> 00041 #include <corelib/request_status.hpp> 00042 00043 00044 /** @addtogroup Diagnostics 00045 * 00046 * @{ 00047 */ 00048 00049 00050 BEGIN_NCBI_SCOPE 00051 00052 ///////////////////////////////////////////////////////////////////////////// 00053 /// Forward declaration 00054 00055 class CPerfLogGuard; 00056 00057 00058 ///////////////////////////////////////////////////////////////////////////// 00059 /// 00060 /// CPerfLogger -- 00061 /// 00062 /// The CPerfLogger measure time spend somewhere, executing some operation 00063 /// and put result to the performance log. Each measurement will result 00064 /// in printing a one-line record to the performance log. 00065 /// This class is designed to measure just one operation. Each measurement 00066 /// should be finished with calling Post() or Discard() method. You can call 00067 /// Start() and Suspend() methods in between as many times as you want. 00068 /// 00069 /// @attention 00070 /// If the logging is off then neither logging nor timing will be done at all. 00071 /// It will however check for incorrect usage and post errors, if any. 00072 /// But if you use next construction 00073 /// perf_logger.Post(...).Print(...) 00074 /// that extra record will be put into the log if the logging is off. 00075 /// Please use PERF_POST macro or PerfLogGuard class to avoid this. 00076 /// @sa 00077 /// PERF_POST, PERF_POST_DB, PerfLogGuard 00078 00079 class NCBI_XNCBI_EXPORT CPerfLogger 00080 { 00081 public: 00082 /// If to start the timing immediately 00083 enum EStart { 00084 eStart, ///< Call Start() immediately after creating 00085 eSuspend ///< Do not start timer (call Start() later) 00086 }; 00087 00088 /// Constructor. Starts the timer by default. 00089 CPerfLogger(EStart state = eStart); 00090 00091 /// Activate and start (or, restart after Suspend()) the timer. 00092 /// @note 00093 /// If the timer is already running, post an error (once). 00094 /// @sa Suspend 00095 void Start(void); 00096 00097 /// Suspend the timer. 00098 /// Call Start() to continue to count time accured before. 00099 /// @sa Start 00100 void Suspend(void); 00101 00102 /// Log the timing; stop and deactivate the timer. 00103 /// @param resource 00104 /// Name of the resource (must be non-empty, else throws an exception). 00105 /// @param status 00106 /// Status of the timed code. 00107 /// @param status_msg 00108 /// Verbal description of the status of the timed code. 00109 /// @note 00110 /// If the timer is already inactive, then post an error (once). 00111 /// @sa Discard 00112 CDiagContext_Extra Post(CRequestStatus::ECode status, 00113 CTempString resource, 00114 CTempString status_msg = CTempString()); 00115 00116 CDiagContext_Extra Post(int status, 00117 CTempString resource, 00118 CTempString status_msg = CTempString()); 00119 00120 /// Discard the timing results; stop and deactivate the timer. 00121 void Discard(void); 00122 00123 /// If the timer is still active, then post an error (once). 00124 /// Usually each measurement should be finished with calling Post() 00125 /// or Discard() method. 00126 ~CPerfLogger(); 00127 00128 /// Is performance logging on, globally? 00129 /// Controlled by CParam(section="Log", entry="PerfLogging", default=false) 00130 static bool IsON(void); 00131 00132 /// Turn performance logging on/off globally. 00133 static void SetON(bool enable = true); 00134 00135 private: 00136 bool x_CheckValidity(const CTempString& err_msg) const; 00137 friend class CPerfLogGuard; 00138 00139 private: 00140 CStopWatch m_StopWatch; ///< Internal timer 00141 CStopWatch::EStart m_TimerState; ///< Internal timer state to save cycles 00142 bool m_IsDiscarded; ///< TRUE if Post() or Discard() is already called 00143 00144 }; 00145 00146 00147 ///////////////////////////////////////////////////////////////////////////// 00148 00149 /// Convenience macro that also saves cycles when the performance logging is 00150 /// globally turned off. 00151 /// 00152 /// CPerfLogger perf_logger; 00153 /// --- Here, running stored proc "123" on server "MSSQL444" which e.g. 00154 /// --- has finished successfully (code 200) in 2.345 seconds: 00155 /// PERF_POST(perf_logger, e200_Ok, "StoredProc123", 00156 /// .Print("dbserver", "MSSQL444") 00157 /// .Print("foo", "bar")); 00158 /// 00159 #define PERF_POST(perf_logger, status, resource, args) \ 00160 do { if ( CPerfLogger::IsON() ) \ 00161 perf_logger.Post(CRequestStatus::status, resource) args; \ 00162 } while (false) 00163 00164 00165 /// Adaptation for logging database performance 00166 /// PERF_POST_DB(perf_logger, e200_Ok, 00167 /// "StoredProc123", "MSSQL444") 00168 /// .Print("foo", "bar")); 00169 /// 00170 #define PERF_POST_DB(perf_logger, status, resource, server, args) \ 00171 do { if ( CPerfLogger::IsON() ) \ 00172 perf_logger.Post(CRequestStatus::status, resource) \ 00173 .Print("dbserver", server) args; \ 00174 } while (false) 00175 00176 00177 00178 ///////////////////////////////////////////////////////////////////////////// 00179 /// 00180 /// CPerfLogGuard -- 00181 /// 00182 /// @attention 00183 /// If the logging is off then neither logging nor timing will be done at all. 00184 /// It will however check for incorrect usage and post errors, if any. 00185 /// 00186 /// If a usage error is encountered, then an error will be posted -- only 00187 /// once per an error type per process. 00188 00189 class NCBI_XNCBI_EXPORT CPerfLogGuard 00190 { 00191 public: 00192 /// Constructor. 00193 /// @param resource 00194 /// Name of the resource (must be non-empty, else throws an exception). 00195 /// @param state 00196 /// Whether to start the timer by default. 00197 CPerfLogGuard(CTempString resource, 00198 CPerfLogger::EStart state = CPerfLogger::eStart); 00199 00200 /// Activate and start (or, restart after Suspend()) the timer. 00201 /// @note 00202 /// If the timer is already running, post an error (once). 00203 /// @sa Suspend 00204 void Start(void); 00205 00206 /// Suspend the timer. 00207 /// Call Start() to continue to count time accured before. 00208 /// @sa Start 00209 void Suspend(void); 00210 00211 /// Add info to the resource's description 00212 CPerfLogGuard& AddParameter(CTempString name, CTempString value); 00213 00214 /// Write the collected resource info and timing to the log. 00215 /// @param status 00216 /// Status of the timed code. 00217 /// @param status_msg 00218 /// Verbal description of the status of the timed code. 00219 /// @note 00220 /// After this any action on this guard will be an error (and no-op). 00221 void Post(CRequestStatus::ECode status, 00222 CTempString status_msg = CTempString()); 00223 00224 void Post(int status, 00225 CTempString status_msg = CTempString()); 00226 00227 /// Discard the results. 00228 /// @note 00229 /// After this any action on this guard will be an error (and no-op). 00230 void Discard(void); 00231 00232 /// If Post() or Discard() have not been called, then log the collected 00233 /// info with status 500. 00234 ~CPerfLogGuard(); 00235 00236 private: 00237 CPerfLogger m_Logger; 00238 string m_Resource; 00239 SDiagMessage::TExtraArgs m_Parameters; 00240 }; 00241 00242 00243 /* @} */ 00244 00245 00246 //============================================================================= 00247 // 00248 // Inline class methods 00249 // 00250 //============================================================================= 00251 00252 // 00253 // CPerfLogger 00254 // 00255 00256 inline 00257 CPerfLogger::CPerfLogger(EStart state) 00258 { 00259 m_IsDiscarded = false; 00260 m_TimerState = CStopWatch::eStop; 00261 if ( state == eStart ) { 00262 Start(); 00263 } 00264 } 00265 00266 00267 inline 00268 void CPerfLogger::Start() 00269 { 00270 if ( !x_CheckValidity("Start") ) { 00271 return; 00272 } 00273 if ( m_TimerState == CStopWatch::eStart ) { 00274 ERR_POST_ONCE(Error << "CPerfLogger timer is already started"); 00275 return; 00276 } 00277 if ( CPerfLogger::IsON() ) { 00278 m_StopWatch.Start(); 00279 } 00280 m_TimerState = CStopWatch::eStart; 00281 } 00282 00283 00284 inline 00285 void CPerfLogger::Suspend() 00286 { 00287 if ( !x_CheckValidity("Suspend") ) { 00288 return; 00289 } 00290 if ( CPerfLogger::IsON() ) { 00291 m_StopWatch.Stop(); 00292 } 00293 m_TimerState = CStopWatch::eStop; 00294 } 00295 00296 00297 inline CDiagContext_Extra 00298 CPerfLogger::Post(CRequestStatus::ECode status, 00299 CTempString resource, 00300 CTempString status_msg) 00301 { 00302 return Post((int)status, resource, status_msg); 00303 } 00304 00305 00306 inline 00307 void CPerfLogger::Discard() 00308 { 00309 // We don't need to "stop" CStopWatch here, it is nor really running. 00310 m_TimerState = CStopWatch::eStop; 00311 m_IsDiscarded = true; 00312 } 00313 00314 00315 inline 00316 CPerfLogger::~CPerfLogger() 00317 { 00318 if ( !m_IsDiscarded && m_TimerState != CStopWatch::eStop ) { 00319 ERR_POST_ONCE(Error << "CPerfLogger timer is still running"); 00320 } 00321 } 00322 00323 00324 inline 00325 bool CPerfLogger::x_CheckValidity(const CTempString& err_msg) const 00326 { 00327 if ( m_IsDiscarded ) { 00328 ERR_POST_ONCE(Error << err_msg << "() cannot be done, " \ 00329 "CPerfLogger is already discarded"); 00330 return false; 00331 } 00332 return true; 00333 } 00334 00335 00336 // 00337 // CPerfLogGuard 00338 // 00339 00340 inline 00341 CPerfLogGuard::CPerfLogGuard(CTempString resource, CPerfLogger::EStart state) 00342 : m_Logger(state), m_Resource(resource) 00343 { 00344 if ( resource.empty() ) { 00345 NCBI_THROW(CCoreException, eInvalidArg, 00346 "CPerfLogGuard:: resource name is not specified"); 00347 } 00348 } 00349 00350 00351 inline 00352 CPerfLogGuard::~CPerfLogGuard() 00353 { 00354 try { 00355 if ( !m_Logger.m_IsDiscarded ) { 00356 Post(CRequestStatus::e500_InternalServerError); 00357 } 00358 } 00359 catch (CCoreException&) { 00360 } 00361 } 00362 00363 00364 inline 00365 void CPerfLogGuard::Start() 00366 { 00367 m_Logger.Start(); 00368 } 00369 00370 00371 inline 00372 void CPerfLogGuard::Suspend() 00373 { 00374 m_Logger.Suspend(); 00375 } 00376 00377 00378 inline 00379 CPerfLogGuard& CPerfLogGuard::AddParameter(CTempString name, CTempString value) 00380 { 00381 if ( m_Logger.m_IsDiscarded ) { 00382 ERR_POST_ONCE(Error << "AddParameter() cannot be done, " \ 00383 "CPerfLogGuard is already discarded"); 00384 } else { 00385 m_Parameters.push_back(SDiagMessage::TExtraArg(name, value)); 00386 } 00387 return *this; 00388 } 00389 00390 00391 inline 00392 void CPerfLogGuard::Post(CRequestStatus::ECode status, 00393 CTempString status_msg) 00394 { 00395 return Post((int)status, status_msg); 00396 } 00397 00398 00399 inline 00400 void CPerfLogGuard::Discard() 00401 { 00402 m_Logger.Discard(); 00403 } 00404 00405 00406 00407 END_NCBI_SCOPE 00408 00409 00410 #endif /* CORELIB___PERF_LOG__HPP */
1.7.5.1
Modified on Wed May 23 12:56:01 2012 by modify_doxy.py rev. 337098