00001 #ifndef CORELIB___NCBIDIAG__HPP 00002 #define CORELIB___NCBIDIAG__HPP 00003 00004 /* $Id: ncbidiag.hpp 175832 2009-11-10 22:43:04Z 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 00030 * 00031 * 00032 */ 00033 00034 /// @file ncbidiag.hpp 00035 /// 00036 /// Defines NCBI C++ diagnostic APIs, classes, and macros. 00037 /// 00038 /// More elaborate documentation could be found in: 00039 /// http://www.ncbi.nlm.nih.gov/IEB/ToolBox/CPP_DOC/ 00040 /// programming_manual/diag.html 00041 00042 00043 #include <corelib/ncbistre.hpp> 00044 #include <list> 00045 #include <vector> 00046 #include <map> 00047 #include <memory> 00048 #include <stdexcept> 00049 00050 00051 /** @addtogroup Diagnostics 00052 * 00053 * @{ 00054 */ 00055 00056 00057 BEGIN_NCBI_SCOPE 00058 00059 /// Incapsulate compile time information such as 00060 /// _FILE_ _LINE NCBI_MODULE 00061 /// NCBI_MODULE is used only in .cpp file 00062 /// @sa 00063 /// DIAG_COMPILE_INFO 00064 class CDiagCompileInfo 00065 { 00066 public: 00067 // DO NOT create CDiagCompileInfo directly 00068 // use macro DIAG_COMPILE_INFO instead! 00069 00070 CDiagCompileInfo(void); 00071 00072 CDiagCompileInfo(const char* file, 00073 int line, 00074 const char* curr_funct = NULL, 00075 const char* module = NULL); 00076 00077 CDiagCompileInfo(const string& file, 00078 int line, 00079 const string& curr_funct, 00080 const string& module); 00081 00082 ~CDiagCompileInfo(void); 00083 00084 const char* GetFile (void) const; 00085 const char* GetModule (void) const; 00086 int GetLine (void) const; 00087 const string& GetClass (void) const; 00088 const string& GetFunction(void) const; 00089 00090 private: 00091 00092 void ParseCurrFunctName(void) const; 00093 00094 // Check if module needs to be set 00095 bool x_NeedModule(void) const; 00096 00097 private: 00098 const char* m_File; 00099 const char* m_Module; 00100 int m_Line; 00101 00102 const char* m_CurrFunctName; 00103 mutable bool m_Parsed; 00104 mutable string m_ClassName; 00105 mutable string m_FunctName; 00106 00107 // Storage for data passed as strings rather than char*. 00108 char* m_StrFile; 00109 char* m_StrModule; 00110 char* m_StrCurrFunctName; 00111 }; 00112 00113 const char* g_DiagUnknownFunction(void); 00114 00115 /// Get current function name. 00116 /// Defined inside of either a method or a function body only. 00117 // Based on boost's BOOST_CURRENT_FUNCTION 00118 00119 #if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600)) 00120 # define NCBI_CURRENT_FUNCTION __PRETTY_FUNCTION__ 00121 #elif defined(__FUNCSIG__) 00122 # define NCBI_CURRENT_FUNCTION __FUNCSIG__ 00123 #elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500)) 00124 # define NCBI_CURRENT_FUNCTION __FUNCTION__ 00125 #elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550) 00126 # define NCBI_CURRENT_FUNCTION __FUNC__ 00127 #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) 00128 # define NCBI_CURRENT_FUNCTION __func__ 00129 #else 00130 # define NCBI_CURRENT_FUNCTION NCBI_NS_NCBI::g_DiagUnknownFunction() 00131 #endif 00132 00133 00134 /// Set default module name based on NCBI_MODULE macro 00135 /// 00136 /// @sa DIAG_COMPILE_INFO 00137 #define NCBI_MAKE_MODULE(module) NCBI_AS_STRING(module) 00138 00139 /// Make compile time diagnostic information object 00140 /// to use in CNcbiDiag and CException. 00141 /// 00142 /// This macro along with functionality of macro NCBI_MAKE_MODULE and 00143 /// of constructor CDiagCompileInfo ensures that if variable NCBI_MODULE 00144 /// will be defined then its value will be used as module name, but if it 00145 /// isn't defined then module name in CDiagCompileInfo will be empty. 00146 /// "Checking" of definition of NCBI_MODULE is performed at the moment 00147 /// of macro issuing so you can define and redefine NCBI_MODULE several 00148 /// times during one cpp-file. But BE WARNED that macro NCBI_MODULE is 00149 /// considered as not defined when used in any header file. So if you want 00150 /// for example make some error posting from inline function defined in 00151 /// hpp-file and want your custom module name to be shown in error 00152 /// message then you have to use MDiagModule manipulator as following: 00153 /// 00154 /// ERR_POST_X(1, MDiagModule("MY_MODULE_NAME") << "Error message" ); 00155 /// 00156 /// @sa 00157 /// CDiagCompileInfo 00158 #define DIAG_COMPILE_INFO \ 00159 NCBI_NS_NCBI::CDiagCompileInfo(__FILE__, \ 00160 __LINE__, \ 00161 NCBI_CURRENT_FUNCTION, \ 00162 NCBI_MAKE_MODULE(NCBI_MODULE)) 00163 00164 00165 00166 00167 /// Error posting with file, line number information but without error codes. 00168 /// This macro is deprecated and it's strongly recomended to move 00169 /// in all projects (except tests) to macro ERR_POST_X to make possible more 00170 /// flexible error statistics and logging. 00171 /// 00172 /// @sa 00173 /// ERR_POST_EX, ERR_POST_X 00174 #define ERR_POST(message) \ 00175 ( NCBI_NS_NCBI::CNcbiDiag(DIAG_COMPILE_INFO).GetRef() \ 00176 << message \ 00177 << NCBI_NS_NCBI::Endm ) 00178 00179 00180 /// Log message only without severity, location, prefix information. 00181 /// This macro is deprecated and it's strongly recomended to move 00182 /// in all projects (except tests) to macro LOG_POST_X to make possible more 00183 /// flexible error statistics and logging. 00184 /// 00185 /// @sa 00186 /// LOG_POST_EX, LOG_POST_X 00187 #define LOG_POST(message) \ 00188 ( NCBI_NS_NCBI::CNcbiDiag(DIAG_COMPILE_INFO, \ 00189 eDiag_Error, \ 00190 eDPF_Log | eDPF_IsMessage).GetRef() \ 00191 << message \ 00192 << NCBI_NS_NCBI::Endm ) 00193 00194 /// Error posting with error codes. 00195 /// This macro should be used only when you need to make non-constant 00196 /// error subcode. In all other cases it's strongly recomended to move 00197 /// in all projects (except tests) to macro ERR_POST_X to make possible more 00198 /// flexible error statistics and logging. 00199 /// 00200 /// @sa 00201 /// ERR_POST, ERR_POST_X 00202 #define ERR_POST_EX(err_code, err_subcode, message) \ 00203 ( NCBI_NS_NCBI::CNcbiDiag(DIAG_COMPILE_INFO).GetRef() \ 00204 << NCBI_NS_NCBI::ErrCode( (err_code), (err_subcode) ) \ 00205 << message \ 00206 << NCBI_NS_NCBI::Endm ) 00207 00208 /// Log posting with error codes. 00209 /// This macro should be used only when you need to make non-constant 00210 /// error subcode. In all other cases it's strongly recomended to move 00211 /// in all projects (except tests) to macro LOG_POST_X to make possible more 00212 /// flexible error statistics and logging. 00213 /// 00214 /// @sa 00215 /// LOG_POST, LOG_POST_X 00216 #define LOG_POST_EX(err_code, err_subcode, message) \ 00217 ( NCBI_NS_NCBI::CNcbiDiag(eDiag_Error, \ 00218 eDPF_Log | eDPF_IsMessage).GetRef() \ 00219 << NCBI_NS_NCBI::ErrCode( (err_code), (err_subcode) ) \ 00220 << message << NCBI_NS_NCBI::Endm ) 00221 00222 00223 /// Define global error code name with given value (err_code) and given 00224 /// maximum value of error subcode within this code. To use defined error 00225 /// code you need to define symbol NCBI_USE_ERRCODE_X with name as its value. 00226 /// This error code is used only in macros LOG_POST_X and ERR_POST_X. Maximum 00227 /// value of error subcode is being checked during compilation and 00228 /// exists for developers to know what code they can use in next inserted 00229 /// ERR_POST_X call (i.e. when one want to insert new ERR_POST_X call he has 00230 /// to find definition of error code used in the source file, increase value 00231 /// of maximum subcode and put result in ERR_POST_X call). 00232 /// Definition of error code and its maximum subcode can be split into 2 00233 /// independent macros to avoid recompilation of everything that includes 00234 /// header with error code definition. For more information about it see 00235 /// NCBI_DEFINE_ERR_SUBCODE_X. 00236 /// Macro MUST be used inside ncbi scope. 00237 /// 00238 /// Example: 00239 /// NCBI_DEFINE_ERRCODE_X(Corelib_Util, 110, 5); 00240 /// ... 00241 /// #define NCBI_USE_ERRCODE_X Corelib_Util 00242 /// ... 00243 /// ERR_POST_X(3, "My error message with variables " << var); 00244 /// 00245 /// 00246 /// @sa 00247 /// NCBI_DEFINE_ERR_SUBCODE_X, LOG_POST_X, ERR_POST_X, 00248 /// NCBI_ERRCODE_X, NCBI_MAX_ERR_SUBCODE_X 00249 #define NCBI_DEFINE_ERRCODE_X(name, err_code, max_err_subcode) \ 00250 namespace err_code_x { \ 00251 enum { \ 00252 eErrCodeX_##name = err_code, \ 00253 eErrCodeX_Max_##name = max_err_subcode \ 00254 }; \ 00255 template <bool dummy> \ 00256 struct SErrCodeX_Max_##name { \ 00257 enum { \ 00258 value = max_err_subcode, \ 00259 dumm_dumm = int(dummy) \ 00260 }; \ 00261 }; \ 00262 } \ 00263 extern void err_code_x__dummy_for_semicolon(void) 00264 00265 /// Define maximum value of subcode for the error code currently in use. 00266 /// Currently used error code is defined by macro NCBI_USE_ERRCODE_X. This 00267 /// macro is a simplified version of NCBI_DEFINE_ERR_SUBCODE_XX and can be 00268 /// handy to use when some error code is used only in one source file and no 00269 /// other error code is used in the same source file. 00270 /// To use this macro you must put 0 as max_err_subcode in 00271 /// NCBI_DEFINE_ERRCODE_X macro. Otherwise compilation error will occur. 00272 /// Macro MUST be used inside ncbi scope. 00273 /// 00274 /// Example: 00275 /// NCBI_DEFINE_ERRCODE_X(Corelib_Util, 110, 0); 00276 /// ... 00277 /// #define NCBI_USE_ERRCODE_X Corelib_Util 00278 /// NCBI_DEFINE_ERR_SUBCODE_X(5); 00279 /// ... 00280 /// ERR_POST_X(3, "My error message with variables " << var); 00281 /// 00282 /// 00283 /// @sa 00284 /// NCBI_DEFINE_ERRCODE_X, NCBI_DEFINE_ERR_SUBCODE_XX 00285 #define NCBI_DEFINE_ERR_SUBCODE_X(max_err_subcode) \ 00286 NCBI_DEFINE_ERR_SUBCODE_XX(NCBI_USE_ERRCODE_X, max_err_subcode) 00287 00288 /// Define maximum value of subcode for particular error code name. 00289 /// To use this macro you must put 0 as max_err_subcode in 00290 /// NCBI_DEFINE_ERRCODE_X macro. Otherwise compilation error will occur. 00291 /// Macro can be used only once per compilation unit. 00292 /// Macro MUST be used inside ncbi scope. 00293 /// 00294 /// Example: 00295 /// NCBI_DEFINE_ERRCODE_X(Corelib_Util, 110, 0); 00296 /// ... 00297 /// NCBI_DEFINE_ERR_SUBCODE_XX(Corelib_Util, 5); 00298 /// ... 00299 /// #define NCBI_USE_ERRCODE_X Corelib_Util 00300 /// ... 00301 /// ERR_POST_X(3, "My error message with variables " << var); 00302 /// 00303 /// 00304 /// @sa 00305 /// NCBI_DEFINE_ERRCODE_X 00306 #define NCBI_DEFINE_ERR_SUBCODE_XX(name, max_err_subcode) \ 00307 NCBI_CHECK_ERRCODE_USAGE(name) \ 00308 namespace err_code_x { \ 00309 template <> \ 00310 struct NCBI_NAME2(SErrCodeX_Max_, name)<true> { \ 00311 enum { \ 00312 value = max_err_subcode \ 00313 }; \ 00314 }; \ 00315 } 00316 00317 00318 /// Returns value of error code by its name defined by NCBI_DEFINE_ERRCODE_X 00319 /// 00320 /// @sa NCBI_DEFINE_ERRCODE_X 00321 #define NCBI_ERRCODE_X_NAME(name) \ 00322 NCBI_NS_NCBI::err_code_x::NCBI_NAME2(eErrCodeX_, name) 00323 00324 /// Returns currently set default error code. Default error code is set by 00325 /// definition of NCBI_USE_ERRCODE_X with name of error code as its value. 00326 /// 00327 /// @sa NCBI_DEFINE_ERRCODE_X 00328 #define NCBI_ERRCODE_X NCBI_ERRCODE_X_NAME(NCBI_USE_ERRCODE_X) 00329 00330 /// Returns maximum value of error subcode within error code with given name. 00331 /// 00332 /// @sa NCBI_DEFINE_ERRCODE_X 00333 #define NCBI_MAX_ERR_SUBCODE_X_NAME(name) \ 00334 NCBI_NS_NCBI::err_code_x::NCBI_NAME2(SErrCodeX_Max_, name)<true>::value 00335 00336 /// Returns maximum value of error subcode within current default error code. 00337 /// 00338 /// @sa NCBI_DEFINE_ERRCODE_X 00339 #define NCBI_MAX_ERR_SUBCODE_X \ 00340 NCBI_MAX_ERR_SUBCODE_X_NAME(NCBI_USE_ERRCODE_X) 00341 00342 00343 /// Template structure used to point out wrong error subcode in 00344 /// ERR_POST_X, STD_CATCH_X and alike macros. When error subcode that is 00345 /// greater than maximum defined in NCBI_DEFINE_ERRCODE_X or 00346 /// NCBI_DEFINE_ERR_SUBCODE_X will be used compiler will give an error and in 00347 /// text of this error you'll see the name of this structure. In parameters of 00348 /// template instantiation (that will be also shown in error message) you'll 00349 /// see error code currently active, error subcode used in *_POST_X macro and 00350 /// maximum error subcode valid for active error code. 00351 /// 00352 /// @sa 00353 /// NCBI_DEFINE_ERRCODE_X, NCBI_DEFINE_ERR_SUBCODE_X, LOG_POST_X, ERR_POST_X 00354 template <int errorCode, int errorSubcode, int maxErrorSubcode, bool isWrong> 00355 struct WRONG_ERROR_SUBCODE_IN_POST_MACRO; 00356 00357 /// Specialization of template: when error subcode is valid existence 00358 /// of this specialization will be valuable for not issuing compiler error. 00359 template <int errorCode, int errorSubcode, int maxErrorSubcode> 00360 struct WRONG_ERROR_SUBCODE_IN_POST_MACRO 00361 <errorCode, errorSubcode, maxErrorSubcode, false> { 00362 enum {valid = 1}; 00363 }; 00364 00365 /// Template structure used to point out incorrect usage of 00366 /// NCBI_DEFINE_ERR_SUBCODE_X macro i.e. when it's used for error code defined 00367 /// with non-zero maximum subcode in NCBI_DEFINE_ERRCODE_X macro. 00368 /// 00369 /// @sa 00370 /// NCBI_DEFINE_ERRCODE_X, NCBI_DEFINE_ERR_SUBCODE_X 00371 template <int errorCode, bool isWrong> 00372 struct WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO; 00373 00374 /// Specialization of template: when usage of NCBI_DEFINE_ERR_SUBCODE_X is 00375 /// correct existence of this specialization will be valuable for not issuing 00376 /// compiler error. 00377 template <int errorCode> 00378 struct WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO<errorCode, false> { 00379 enum {valid = 1}; 00380 }; 00381 00382 /// Check that NCBI_DEFINE_ERR_SUBCODE_X is used for correctly defined error 00383 /// code. 00384 #define NCBI_CHECK_ERRCODE_USAGE(name) \ 00385 inline void NCBI_NAME2(s_ErrCodeCheck_, name) ( \ 00386 NCBI_NS_NCBI::WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO < \ 00387 NCBI_ERRCODE_X_NAME(name), \ 00388 NCBI_NS_NCBI::err_code_x::eErrCodeX_Max_##name != 0> \ 00389 err_subcode) \ 00390 {} 00391 00392 00393 /// Additional dummy function for use in NCBI_CHECK_ERR_SUBCODE_X macro 00394 inline void CheckErrSubcodeX(int) 00395 {} 00396 00397 #if defined(NCBI_COMPILER_GCC) && NCBI_COMPILER_VERSION < 350 00398 00399 /// Issue compile-time error if error subcode given is not valid for given 00400 /// error code name. 00401 /// For early versions of gcc used a bit different design to make error 00402 /// message more clear to understand. 00403 /// 00404 /// @sa LOG_POST_X, ERR_POST_X 00405 #define NCBI_CHECK_ERR_SUBCODE_X_NAME(name, subcode) \ 00406 NCBI_NS_NCBI::CheckErrSubcodeX( \ 00407 NCBI_NS_NCBI::WRONG_ERROR_SUBCODE_IN_POST_MACRO< \ 00408 NCBI_ERRCODE_X_NAME(name), subcode, \ 00409 NCBI_MAX_ERR_SUBCODE_X_NAME(name), \ 00410 ((unsigned int)subcode > \ 00411 (unsigned int)NCBI_MAX_ERR_SUBCODE_X_NAME(name)) \ 00412 >::valid \ 00413 ) 00414 00415 #else // if defined(NCBI_COMPILER_GCC) && NCBI_COMPILER_VERSION < 350 00416 00417 /// Issue compile-time error if error subcode given is not valid for given 00418 /// error code name. 00419 /// This design is used for all compilers except early versions of gcc. 00420 /// Though for MIPSpro and ICC it's not enough to make error message clear 00421 /// (see addition below). 00422 /// 00423 /// @sa LOG_POST_X, ERR_POST_X 00424 #define NCBI_CHECK_ERR_SUBCODE_X_NAME(name, subcode) \ 00425 NCBI_NS_NCBI::CheckErrSubcodeX( \ 00426 (int)sizeof(NCBI_NS_NCBI::WRONG_ERROR_SUBCODE_IN_POST_MACRO< \ 00427 NCBI_ERRCODE_X_NAME(name), subcode, \ 00428 NCBI_MAX_ERR_SUBCODE_X_NAME(name), \ 00429 ((unsigned int)subcode > \ 00430 (unsigned int)NCBI_MAX_ERR_SUBCODE_X_NAME(name)) \ 00431 >) \ 00432 ) 00433 00434 #endif // if defined(NCBI_COMPILER_GCC) && NCBI_COMPILER_VERSION < 350 else 00435 00436 /// Issue compile-time error if error subcode given is not valid for current 00437 /// error code. 00438 #define NCBI_CHECK_ERR_SUBCODE_X(subcode) \ 00439 NCBI_CHECK_ERR_SUBCODE_X_NAME(NCBI_USE_ERRCODE_X, subcode) 00440 00441 #if defined(NCBI_COMPILER_ICC) || defined(NCBI_COMPILER_MIPSPRO) 00442 00443 /// Additional not implemented template structure for use in 00444 /// WRONG_ERROR_SUBCODE_IN_POST_MACRO structure specialization 00445 template <int x> 00446 struct WRONG_ERROR_SUBCODE_IN_POST_MACRO_2; 00447 00448 /// Specialization of template structure used for ICC and MIPSpro 00449 /// If this specialization doesn't exist these compilers doesn't show name 00450 /// of unimplemented structure in error message. But when this specialization 00451 /// exists and uses recursively another not implemented template structure 00452 /// then WRONG_ERROR_SUBCODE_IN_POST_MACRO appears in error message and it 00453 /// becomes clearer. 00454 template <int errorCode, int errorSubcode, int maxErrorSubcode> 00455 struct WRONG_ERROR_SUBCODE_IN_POST_MACRO 00456 <errorCode, errorSubcode, maxErrorSubcode, true> { 00457 typedef char t[sizeof(WRONG_ERROR_SUBCODE_IN_POST_MACRO_2<errorCode>)]; 00458 }; 00459 00460 /// Additional not implemented template structure for use in 00461 /// WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO structure specialization 00462 template <int x> 00463 struct WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO_2; 00464 00465 /// Specialization of template structure used for ICC and MIPSpro 00466 /// If this specialization doesn't exist these compilers doesn't show name 00467 /// of unimplemented structure in error message. But when this specialization 00468 /// exists and uses recursively another not implemented template structure 00469 /// then WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO appears in error message and 00470 /// it becomes clearer. 00471 template <int errorCode> 00472 struct WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO<errorCode, true> { 00473 typedef char t[sizeof( 00474 WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO_2<errorCode>)]; 00475 }; 00476 00477 #endif // if defined(NCBI_COMPILER_ICC) || defined(NCBI_COMPILER_MIPSPRO) 00478 00479 00480 /// Error posting with default error code and given error subcode. Also 00481 /// checks subcode correctness. When error subcode is incorrect (greater than 00482 /// defined in NCBI_DEFINE_ERRCODE_X) compile-time error is issued. 00483 /// All calls to ERR_POST_X or LOG_POST_X under the same default error code 00484 /// MUST be with deferent error subcodes to make possible more 00485 /// flexible error statistics and logging. 00486 /// If using of macro leads to compile errors containing in message strings 00487 /// like "err_code_x" or "ErrCodeX" then you didn't defined error code name 00488 /// with NCBI_DEFINE_ERRCODE_X macro or didn't selected current default 00489 /// error code with valid NCBI_USE_ERRCODE_X definition. 00490 /// This macro allows the use of only constant error subcodes 00491 /// (integer literals or enum constants). If you need to make variable error 00492 /// subcode you need to use macro ERR_POST_EX as follows: 00493 /// 00494 /// NCBI_DEFINE_ERRCODE_X(Corelib_Util, 110, 5); 00495 /// ... 00496 /// #define NCBI_USE_ERRCODE_X Corelib_Util 00497 /// ... 00498 /// ERR_POST_EX(NCBI_ERRCODE_X, my_subcode, 00499 /// "My error message with variables " << var); 00500 /// 00501 /// Or in more complicated way: 00502 /// 00503 /// NCBI_DEFINE_ERRCODE_X(Corelib_Util, 110, 5); 00504 /// ... 00505 /// // no need to define NCBI_USE_ERRCODE_X 00506 /// ... 00507 /// ERR_POST_EX(NCBI_ERRCODE_X_NAME(Corelib_Util), my_subcode, 00508 /// "My error message with variables " << var); 00509 /// 00510 /// It's strongly recomended to use macro NCBI_CHECK_ERR_SUBCODE_X 00511 /// (or NCBI_CHECK_ERR_SUBCODE_X_NAME in complicated case) to check validity 00512 /// of error subcodes in places where variable 'my_subcode' is assigned. 00513 /// 00514 /// 00515 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, ERR_POST_EX 00516 #define ERR_POST_X(err_subcode, message) \ 00517 ERR_POST_XX(NCBI_USE_ERRCODE_X, err_subcode, message) 00518 00519 /// Log posting with default error code and given error subcode. See comments 00520 /// to ERR_POST_X for clarifying the way of use and details of behaviour 00521 /// of this macro. 00522 /// 00523 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, ERR_POST_X, LOG_POST_EX 00524 #define LOG_POST_X(err_subcode, message) \ 00525 LOG_POST_XX(NCBI_USE_ERRCODE_X, err_subcode, message) 00526 00527 /// Error posting with error code having given name and with given error 00528 /// subcode. Macro must be placed in headers instead of ERR_POST_X to not 00529 /// confuse default error codes used in sources where this header is included. 00530 /// 00531 /// @sa NCBI_DEFINE_ERRCODE_X, ERR_POST_X 00532 #define ERR_POST_XX(error_name, err_subcode, message) \ 00533 ( (NCBI_CHECK_ERR_SUBCODE_X_NAME(error_name, err_subcode)), \ 00534 ERR_POST_EX(NCBI_ERRCODE_X_NAME(error_name), err_subcode, message) ) 00535 00536 /// Log posting with error code having given name and with given error 00537 /// subcode. Macro must be placed in headers instead of LOG_POST_X to not 00538 /// confuse default error codes used in sources where this header is included. 00539 /// 00540 /// @sa NCBI_DEFINE_ERRCODE_X, LOG_POST_X 00541 #define LOG_POST_XX(error_name, err_subcode, message) \ 00542 ( (NCBI_CHECK_ERR_SUBCODE_X_NAME(error_name, err_subcode)), \ 00543 LOG_POST_EX(NCBI_ERRCODE_X_NAME(error_name), err_subcode, message) ) 00544 00545 00546 /// Common code for making log or error posting only given number of times 00547 /// during program execution. This macro MUST not be used outside 00548 /// this header. 00549 #define NCBI_REPEAT_POST_N_TIMES(post_macro, count, params) \ 00550 do { \ 00551 static volatile int sx_to_show = (count); \ 00552 int to_show = sx_to_show; \ 00553 if ( to_show > 0 ) { \ 00554 sx_to_show = to_show - 1; \ 00555 post_macro params; /* parenthesis are in params */ \ 00556 } \ 00557 } while ( false ) 00558 00559 00560 /// Log posting only given number of times during program execution. 00561 #define LOG_POST_N_TIMES(count, message) \ 00562 NCBI_REPEAT_POST_N_TIMES( LOG_POST, count, (message) ) 00563 00564 /// Error posting only given number of times during program execution. 00565 #define ERR_POST_N_TIMES(count, message) \ 00566 NCBI_REPEAT_POST_N_TIMES( ERR_POST, count, (message) ) 00567 00568 /// Log posting only once during program execution. 00569 #define LOG_POST_ONCE(message) LOG_POST_N_TIMES(1, message) 00570 00571 /// Error posting only once during program execution. 00572 #define ERR_POST_ONCE(message) ERR_POST_N_TIMES(1, message) 00573 00574 00575 /// Log posting only given number of times during program execution 00576 /// with default error code and given error subcode. 00577 /// 00578 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, LOG_POST_X 00579 #define LOG_POST_X_N_TIMES(count, err_subcode, message) \ 00580 NCBI_REPEAT_POST_N_TIMES( LOG_POST_X, count, (err_subcode, message) ) 00581 00582 /// Error posting only given number of times during program execution 00583 /// with default error code and given error subcode. 00584 /// 00585 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, ERR_POST_X 00586 #define ERR_POST_X_N_TIMES(count, err_subcode, message) \ 00587 NCBI_REPEAT_POST_N_TIMES( ERR_POST_X, count, (err_subcode, message) ) 00588 00589 /// Log posting only once during program execution with default 00590 /// error code and given error subcode. 00591 /// 00592 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, LOG_POST_X 00593 #define LOG_POST_X_ONCE(err_subcode, message) \ 00594 LOG_POST_X_N_TIMES(1, err_subcode, message) 00595 00596 /// Error posting only once during program execution with default 00597 /// error code and given error subcode. 00598 /// 00599 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, ERR_POST_X 00600 #define ERR_POST_X_ONCE(err_subcode, message) \ 00601 ERR_POST_X_N_TIMES(1, err_subcode, message) 00602 00603 00604 /// Log posting only given number of times during program execution 00605 /// with given error code name and given error subcode. 00606 /// 00607 /// @sa NCBI_DEFINE_ERRCODE_X, LOG_POST_XX 00608 #define LOG_POST_XX_N_TIMES(count, error_name, err_subcode, message) \ 00609 NCBI_REPEAT_POST_N_TIMES( LOG_POST_XX, count, \ 00610 (error_name, err_subcode, message) ) 00611 00612 /// Error posting only given number of times during program execution 00613 /// with given error code name and given error subcode. 00614 /// 00615 /// @sa NCBI_DEFINE_ERRCODE_X, ERR_POST_XX 00616 #define ERR_POST_XX_N_TIMES(count, error_name, err_subcode, message) \ 00617 NCBI_REPEAT_POST_N_TIMES( ERR_POST_XX, count, \ 00618 (error_name, err_subcode, message) ) 00619 00620 /// Log posting only once during program execution with given 00621 /// error code name and given error subcode. 00622 /// 00623 /// @sa NCBI_DEFINE_ERRCODE_X, LOG_POST_XX 00624 #define LOG_POST_XX_ONCE(error_name, err_subcode, message) \ 00625 LOG_POST_XX_N_TIMES(1, error_name, err_subcode, message) 00626 00627 /// Error posting only once during program execution with given 00628 /// error code name and given error subcode. 00629 /// 00630 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, ERR_POST_XX 00631 #define ERR_POST_XX_ONCE(error_name, err_subcode, message) \ 00632 ERR_POST_XX_N_TIMES(1, error_name, err_subcode, message) 00633 00634 00635 /// Severity level for the posted diagnostics. 00636 enum EDiagSev { 00637 eDiag_Info = 0, ///< Informational message 00638 eDiag_Warning, ///< Warning message 00639 eDiag_Error, ///< Error message 00640 eDiag_Critical, ///< Critical error message 00641 eDiag_Fatal, ///< Fatal error -- guarantees exit(or abort) 00642 // 00643 eDiag_Trace, ///< Trace message 00644 00645 // Limits 00646 eDiagSevMin = eDiag_Info, ///< Verbosity level for min. severity 00647 eDiagSevMax = eDiag_Trace ///< Verbosity level for max. severity 00648 }; 00649 00650 00651 /// Severity level change state. 00652 enum EDiagSevChange { 00653 eDiagSC_Unknown, ///< Status of changing severity is unknown (first call) 00654 eDiagSC_Disable, ///< Disable change severity level 00655 eDiagSC_Enable ///< Enable change severity level 00656 }; 00657 00658 00659 /// Which parts of the diagnostic context should be posted. 00660 /// 00661 /// Generic appearance of the posted message is as follows: 00662 /// 00663 /// "<file>", line <line>: <severity>: (<err_code>.<err_subcode>) 00664 /// [<prefix1>::<prefix2>::<prefixN>] <message>\n 00665 /// <err_code_message>\n 00666 /// <err_code_explanation> 00667 /// 00668 /// Example: 00669 /// 00670 /// - If all flags are set, and prefix string is set to "My prefix", and 00671 /// ERR_POST(eDiag_Warning, "Take care!"): 00672 /// "/home/iam/myfile.cpp", line 33: Warning: (2.11) 00673 /// Module::Class::Function() - [My prefix] Take care! 00674 /// 00675 /// @sa 00676 /// SDiagMessage::Compose() 00677 enum EDiagPostFlag { 00678 eDPF_File = 0x1, ///< Set by default #if _DEBUG; else not set 00679 eDPF_LongFilename = 0x2, ///< Set by default #if _DEBUG; else not set 00680 eDPF_Line = 0x4, ///< Set by default #if _DEBUG; else not set 00681 eDPF_Prefix = 0x8, ///< Set by default (always) 00682 eDPF_Severity = 0x10, ///< Set by default (always) 00683 eDPF_ErrorID = 0x20, ///< Module, error code and subcode 00684 eDPF_DateTime = 0x80, ///< Include date and time 00685 eDPF_ErrCodeMessage = 0x100, ///< Set by default (always) 00686 eDPF_ErrCodeExplanation = 0x200, ///< Set by default (always) 00687 eDPF_ErrCodeUseSeverity = 0x400, ///< Set by default (always) 00688 eDPF_Location = 0x800, ///< Include class and function 00689 ///< if any, not set by default 00690 eDPF_PID = 0x1000, ///< Process ID 00691 eDPF_TID = 0x2000, ///< Thread ID 00692 eDPF_SerialNo = 0x4000, ///< Serial # of the post, process-wide 00693 eDPF_SerialNo_Thread = 0x8000, ///< Serial # of the post, in the thread 00694 eDPF_RequestId = 0x10000, ///< fcgi iteration number or request ID 00695 eDPF_Iteration = 0x10000, ///< @deprecated 00696 eDPF_UID = 0x20000, ///< UID of the log 00697 00698 eDPF_ErrCode = eDPF_ErrorID, ///< @deprecated 00699 eDPF_ErrSubCode = eDPF_ErrorID, ///< @deprecated 00700 /// All flags (except for the "unusual" ones!) 00701 eDPF_All = 0xFFFFF, 00702 00703 /// Default flags to use when tracing. 00704 #if defined(NCBI_THREADS) 00705 eDPF_Trace = 0xF81F, 00706 #else 00707 eDPF_Trace = 0x581F, 00708 #endif 00709 00710 /// Print the posted message only; without severity, location, prefix, etc. 00711 eDPF_Log = 0x0, 00712 00713 // "Unusual" flags -- not included in "eDPF_All" 00714 eDPF_PreMergeLines = 0x100000, ///< Remove EOLs before calling handler 00715 eDPF_MergeLines = 0x200000, ///< Ask diag.handlers to remove EOLs 00716 eDPF_OmitInfoSev = 0x400000, ///< No sev. indication if eDiag_Info 00717 eDPF_OmitSeparator = 0x800000, ///< No '---' separator before message 00718 00719 eDPF_AppLog = 0x1000000, ///< Post message to application log 00720 eDPF_IsMessage = 0x2000000, ///< Print "Message" severity name. 00721 00722 /// Hint for the current handler to make message output as atomic as 00723 /// possible (e.g. for stream and file handlers). 00724 eDPF_AtomicWrite = 0x4000000, 00725 00726 /// Use global default flags (merge with). 00727 /// @sa SetDiagPostFlag(), UnsetDiagPostFlag(), IsSetDiagPostFlag() 00728 eDPF_Default = 0x10000000, 00729 00730 /// Important bits which should be taken from the globally set flags 00731 /// even if a user attempts to override (or forgets to set) them 00732 /// when calling CNcbiDiag(). 00733 eDPF_ImportantFlagsMask = eDPF_PreMergeLines | 00734 eDPF_MergeLines | 00735 eDPF_OmitInfoSev | 00736 eDPF_OmitSeparator | 00737 eDPF_AtomicWrite, 00738 00739 /// Use flags provided by user as-is, do not allow CNcbiDiag to replace 00740 /// "important" flags by the globally set ones. 00741 eDPF_UseExactUserFlags = 0x20000000 00742 }; 00743 00744 typedef int TDiagPostFlags; ///< Binary OR of "EDiagPostFlag" 00745 00746 00747 /// Application execution states shown in the std prefix 00748 enum EDiagAppState { 00749 eDiagAppState_NotSet, ///< Reserved value, never used in messages 00750 eDiagAppState_AppBegin, ///< AB 00751 eDiagAppState_AppRun, ///< A 00752 eDiagAppState_AppEnd, ///< AE 00753 eDiagAppState_RequestBegin, ///< RB 00754 eDiagAppState_Request, ///< R 00755 eDiagAppState_RequestEnd ///< RE 00756 }; 00757 00758 00759 // Forward declaration of some classes. 00760 class CDiagBuffer; 00761 class CDiagErrCodeInfo; 00762 00763 00764 00765 ///////////////////////////////////////////////////////////////////////////// 00766 /// 00767 /// ErrCode -- 00768 /// 00769 /// Define composition of error code. 00770 /// 00771 /// Currently the error code is an ordered pair of <code, subcode> numbers. 00772 00773 class ErrCode 00774 { 00775 public: 00776 /// Constructor. 00777 ErrCode(int code, int subcode = 0) 00778 : m_Code(code), m_SubCode(subcode) 00779 { } 00780 int m_Code; ///< Major error code number 00781 int m_SubCode; ///< Minor error code number 00782 }; 00783 00784 00785 ///////////////////////////////////////////////////////////////////////////// 00786 /// 00787 /// Severity -- 00788 /// 00789 /// Set post severity to a given level. 00790 00791 class Severity 00792 { 00793 public: 00794 Severity(EDiagSev sev) 00795 : m_Level(sev) {} 00796 EDiagSev m_Level; ///< Severity level 00797 }; 00798 00799 00800 class CNcbiDiag; 00801 00802 ///////////////////////////////////////////////////////////////////////////// 00803 /// 00804 /// MDiagModule -- 00805 /// 00806 /// Manipulator to set Module for CNcbiDiag 00807 00808 class MDiagModule 00809 { 00810 public: 00811 MDiagModule(const char* module); 00812 friend const CNcbiDiag& operator<< (const CNcbiDiag& diag, 00813 const MDiagModule& module); 00814 private: 00815 const char* m_Module; 00816 }; 00817 00818 00819 00820 ///////////////////////////////////////////////////////////////////////////// 00821 /// 00822 /// MDiagClass -- 00823 /// 00824 /// Manipulator to set Class for CNcbiDiag 00825 00826 class MDiagClass 00827 { 00828 public: 00829 MDiagClass(const char* nclass); 00830 friend const CNcbiDiag& operator<< (const CNcbiDiag& diag, 00831 const MDiagClass& nclass); 00832 private: 00833 const char* m_Class; 00834 }; 00835 00836 00837 00838 ///////////////////////////////////////////////////////////////////////////// 00839 /// 00840 /// MDiagFunction -- 00841 /// 00842 /// Manipulator to set Function for CNcbiDiag 00843 00844 class MDiagFunction 00845 { 00846 public: 00847 MDiagFunction(const char* function); 00848 friend const CNcbiDiag& operator<< (const CNcbiDiag& diag, 00849 const MDiagFunction& function); 00850 private: 00851 const char* m_Function; 00852 }; 00853 00854 00855 // 00856 class CException; 00857 class CStackTrace; 00858 00859 00860 ///////////////////////////////////////////////////////////////////////////// 00861 /// 00862 /// CNcbiDiag -- 00863 /// 00864 /// Define the main NCBI Diagnostic class. 00865 00866 00867 class CNcbiDiag 00868 { 00869 public: 00870 /// Constructor. 00871 CNcbiDiag 00872 (EDiagSev sev = eDiag_Error, ///< Severity level 00873 TDiagPostFlags post_flags = eDPF_Default ///< What to post 00874 ); 00875 00876 00877 /// Constructor -- includes the file and line number info 00878 CNcbiDiag 00879 (const CDiagCompileInfo& info, ///< File, line, module 00880 EDiagSev sev = eDiag_Error, ///< Severity level 00881 TDiagPostFlags post_flags = eDPF_Default ///< What to post 00882 ); 00883 00884 /// Destructor. 00885 ~CNcbiDiag(void); 00886 00887 /// Some compilers (e.g. GCC 3.4.0) fail to use temporary objects as 00888 /// function arguments if there's no public copy constructor. 00889 /// Rather than using the temporary, get a reference from this method. 00890 const CNcbiDiag& GetRef(void) const { return *this; } 00891 00892 /// Generic method to post to diagnostic stream. 00893 // Some compilers need to see the body right away, but others need 00894 // to meet CDiagBuffer first. 00895 template<class X> const CNcbiDiag& Put(const void*, const X& x) const 00896 #ifdef NCBI_COMPILER_MSVC 00897 { 00898 m_Buffer.Put(*this, x); 00899 return *this; 00900 } 00901 #else 00902 ; 00903 # define NCBIDIAG_DEFER_GENERIC_PUT 00904 #endif 00905 00906 /// Diagnostic stream manipulator 00907 /// @sa Reset(), Endm() 00908 /// @sa Info(), Warning(), Error(), Critical(), Fatal(), Trace() 00909 typedef const CNcbiDiag& (*FManip)(const CNcbiDiag&); 00910 typedef IOS_BASE& (*FIosManip)(IOS_BASE&); 00911 00912 /// Helper method to post error code and subcode to diagnostic stream. 00913 /// 00914 /// Example: 00915 /// CNcbiDiag() << ErrCode(5,3) << "My message"; 00916 const CNcbiDiag& Put(const ErrCode*, const ErrCode& err_code) const; 00917 00918 /// Helper method to set severity level. 00919 /// 00920 /// Example: 00921 /// CNcbiDiag() << Severity(eDiag_Error) << "My message"; 00922 const CNcbiDiag& Put(const Severity*, const Severity& severity) const; 00923 00924 /// Helper method to post an exception to diagnostic stream. 00925 /// 00926 /// Example: 00927 /// CNcbiDiag() << ex; 00928 template<class X> inline 00929 const CNcbiDiag& Put(const CException*, const X& x) const { 00930 return x_Put(x); 00931 } 00932 00933 /// Helper method to post stack trace to diagnostic stream using 00934 /// standard stack trace formatting. 00935 /// 00936 /// Example: 00937 /// CNcbiDiag() << "My message" << CStackTrace(); 00938 00939 const CNcbiDiag& Put(const CStackTrace*, 00940 const CStackTrace& stacktrace) const; 00941 00942 /// Helper method to handle various diagnostic stream manipulators. 00943 /// 00944 /// For example, to set the message severity level to INFO: 00945 /// CNcbiDiag() << Info << "My message"; 00946 const CNcbiDiag& Put(const FManip, const FManip& manip) const 00947 { 00948 return manip(*this); 00949 } 00950 inline const CNcbiDiag& operator<< (FManip manip) const 00951 { 00952 return manip(*this); 00953 } 00954 const CNcbiDiag& operator<< (FIosManip manip) const; 00955 00956 /// Post the arguments 00957 /// @sa Put() 00958 template<class X> inline const CNcbiDiag& operator<< (const X& x) const 00959 { 00960 return Put(&x, x); 00961 } 00962 00963 // Output manipulators for CNcbiDiag. 00964 00965 /// Reset the content of current message. 00966 friend const CNcbiDiag& Reset (const CNcbiDiag& diag); 00967 00968 /// Flush current message, start new one. 00969 friend const CNcbiDiag& Endm (const CNcbiDiag& diag); 00970 00971 /// Flush current message, then set a severity for the next diagnostic 00972 /// message to INFO 00973 friend const CNcbiDiag& Info (const CNcbiDiag& diag); 00974 00975 /// Flush current message, then set a severity for the next diagnostic 00976 /// message to WARNING 00977 friend const CNcbiDiag& Warning (const CNcbiDiag& diag); 00978 00979 /// Flush current message, then set a severity for the next diagnostic 00980 /// message to ERROR 00981 friend const CNcbiDiag& Error (const CNcbiDiag& diag); 00982 00983 /// Flush current message, then set a severity for the next diagnostic 00984 /// message to CRITICAL ERROR 00985 friend const CNcbiDiag& Critical(const CNcbiDiag& diag); 00986 00987 /// Flush current message, then set a severity for the next diagnostic 00988 /// message to FATAL 00989 friend const CNcbiDiag& Fatal (const CNcbiDiag& diag); 00990 00991 /// Flush current message, then set a severity for the next diagnostic 00992 /// message to TRACE 00993 friend const CNcbiDiag& Trace (const CNcbiDiag& diag); 00994 00995 /// Set IsMessage flag to indicate that the current post is a message. 00996 /// Do not flush current post or change the severity. The flag is reset 00997 /// by the next Flush(). 00998 friend const CNcbiDiag& Message (const CNcbiDiag& diag); 00999 01000 /// Get a common symbolic name for the severity levels. 01001 static const char* SeverityName(EDiagSev sev); 01002 01003 /// Get severity from string. 01004 /// 01005 /// @param str_sev 01006 /// Can be the numeric value or a symbolic name (see 01007 /// CDiagBuffer::sm_SeverityName[]). 01008 /// @param sev 01009 /// Severity level. 01010 /// @return 01011 /// Return TRUE if severity level known; FALSE, otherwise. 01012 01013 static bool StrToSeverityLevel(const char* str_sev, EDiagSev& sev); 01014 01015 /// Set file name to post. 01016 01017 const CNcbiDiag& SetFile(const char* file) const; 01018 01019 /// Set module name. 01020 01021 const CNcbiDiag& SetModule(const char* module) const; 01022 01023 /// Set class name. 01024 01025 const CNcbiDiag& SetClass(const char* nclass) const; 01026 01027 /// Set function name. 01028 01029 const CNcbiDiag& SetFunction(const char* function) const; 01030 01031 /// Set line number for post. 01032 const CNcbiDiag& SetLine(size_t line) const; 01033 01034 /// Set error code and subcode numbers. 01035 const CNcbiDiag& SetErrorCode(int code = 0, int subcode = 0) const; 01036 01037 /// Get severity of the current message. 01038 EDiagSev GetSeverity(void) const; 01039 01040 /// Get file used for the current message. 01041 const char* GetFile(void) const; 01042 01043 /// Get line number for the current message. 01044 size_t GetLine(void) const; 01045 01046 /// Get error code of the current message. 01047 int GetErrorCode(void) const; 01048 01049 /// Get error subcode of the current message. 01050 int GetErrorSubCode(void) const; 01051 01052 /// Get module name of the current message. 01053 const char* GetModule(void) const; 01054 01055 /// Get class name of the current message. 01056 const char* GetClass(void) const; 01057 01058 /// Get function name of the current message. 01059 const char* GetFunction(void) const; 01060 01061 /// Check if filters are passed 01062 01063 bool CheckFilters(void) const; 01064 01065 /// Get post flags for the current message. 01066 /// If the post flags have "eDPF_Default" set, then in the returned flags 01067 /// it will be reset and substituted by current default flags. 01068 TDiagPostFlags GetPostFlags(void) const; 01069 01070 /// Display fatal error message. 01071 01072 static void DiagFatal(const CDiagCompileInfo& info, 01073 const char* message); 01074 /// Display trouble error message. 01075 01076 static void DiagTrouble(const CDiagCompileInfo& info, 01077 const char* message = NULL); 01078 01079 /// Assert specfied expression and report results. 01080 01081 static void DiagAssert(const CDiagCompileInfo& info, 01082 const char* expression, 01083 const char* message = NULL); 01084 01085 /// Display validation message. 01086 01087 static void DiagValidate(const CDiagCompileInfo& info, 01088 const char* expression, 01089 const char* message); 01090 01091 /// Reset IsMessage flag. 01092 void ResetIsMessageFlag(void) const { m_PostFlags &= ~eDPF_IsMessage; } 01093 01094 /// Set important flags to their globally set values 01095 /// @sa EDiagPostFlags 01096 static TDiagPostFlags ForceImportantFlags(TDiagPostFlags flags); 01097 01098 private: 01099 enum EValChngFlags { 01100 fFileIsChanged = 0x1, 01101 fLineIsChanged = 0x2, 01102 fModuleIsChanged = 0x4, 01103 fClassIsChanged = 0x8, 01104 fFunctionIsChanged = 0x10 01105 }; 01106 typedef int TValChngFlags; 01107 01108 mutable EDiagSev m_Severity; ///< Severity level of current msg 01109 mutable int m_ErrCode; ///< Error code 01110 mutable int m_ErrSubCode; ///< Error subcode 01111 CDiagBuffer& m_Buffer; ///< This thread's error msg. buffer 01112 mutable TDiagPostFlags m_PostFlags; ///< Bitwise OR of "EDiagPostFlag" 01113 mutable bool m_CheckFilters; ///< Whether to apply filters 01114 01115 CDiagCompileInfo m_CompileInfo; 01116 01117 mutable string m_File; ///< File name 01118 mutable size_t m_Line; ///< Line number 01119 mutable string m_Module; ///< Module name 01120 mutable string m_Class; ///< Class name 01121 mutable string m_Function; ///< Function name 01122 mutable TValChngFlags m_ValChngFlags; 01123 01124 /// Private replacement for Endm called from manipulators. Unlike Endm, 01125 /// does not reset ErrCode if buffer is not set. 01126 void x_EndMess(void) const; 01127 01128 /// Helper func for the exception-related Put() 01129 /// @sa Put() 01130 const CNcbiDiag& x_Put(const CException& ex) const; 01131 01132 /// Private copy constructor to prohibit copy. 01133 CNcbiDiag(const CNcbiDiag&); 01134 01135 /// Private assignment operator to prohibit assignment. 01136 CNcbiDiag& operator= (const CNcbiDiag&); 01137 }; 01138 01139 01140 01141 ///////////////////////////////////////////////////////////////////////////// 01142 // ATTENTION: the following functions are application-wide, i.e they 01143 // are not local for a particular thread 01144 ///////////////////////////////////////////////////////////////////////////// 01145 01146 01147 /// Check if a specified flag is set. 01148 /// 01149 /// @param flag 01150 /// Flag to check 01151 /// @param flags 01152 /// If eDPF_Default is set for "flags" then use the current global flags on 01153 /// its place (merged with other flags from "flags"). 01154 /// @return 01155 /// "TRUE" if the specified "flag" is set in global "flags" that describes 01156 /// the post settings. 01157 /// @sa SetDiagPostFlag(), UnsetDiagPostFlag() 01158 inline bool IsSetDiagPostFlag(EDiagPostFlag flag, 01159 TDiagPostFlags flags = eDPF_Default); 01160 01161 /// Set global post flags to "flags". 01162 /// If "flags" have flag eDPF_Default set, it will be replaced by the 01163 /// current global post flags. 01164 /// @return 01165 /// Previously set flags 01166 01167 extern TDiagPostFlags SetDiagPostAllFlags(TDiagPostFlags flags); 01168 01169 /// Set the specified flag (globally). 01170 01171 extern void SetDiagPostFlag(EDiagPostFlag flag); 01172 01173 /// Unset the specified flag (globally). 01174 01175 extern void UnsetDiagPostFlag(EDiagPostFlag flag); 01176 01177 /// Versions of the above for extra trace flags. 01178 /// ATTENTION: Thus set trace flags will be ADDED to the regular 01179 /// posting flags. 01180 01181 01182 extern TDiagPostFlags SetDiagTraceAllFlags(TDiagPostFlags flags); 01183 01184 01185 extern void SetDiagTraceFlag(EDiagPostFlag flag); 01186 01187 01188 extern void UnsetDiagTraceFlag(EDiagPostFlag flag); 01189 01190 class CDiagContextThreadData; 01191 01192 /// Guard for collecting diag messages (affects the current thread only). 01193 /// 01194 /// Messages with the severity equal or above 'print' severity will be 01195 /// printed but not collected. Messages having severity below 'print' 01196 /// severity and equal or above 'collect' severity will be collected, 01197 /// and later can be either discarded or printed out upon the guard 01198 /// destruction or when Release() is called. 01199 /// @note 01200 /// Nested guards are allowed. Each guard takes care to restore the 01201 /// severity thresholds set by the previous one. 01202 class CDiagCollectGuard 01203 { 01204 public: 01205 /// Action to perform in guard's destructor 01206 enum EAction { 01207 ePrint, ///< Print all collected messages 01208 eDiscard ///< Discard collected messages, default 01209 }; 01210 01211 /// Set collectable severity to the current post level, 01212 /// print severity is set to critical. 01213 /// The default action is eDiscard. 01214 CDiagCollectGuard(void); 01215 01216 /// Set collectable severity to the current post level, 01217 /// print severity is set to the specified value but can be ignored 01218 /// if it's lower than the currently set post level (or print severity 01219 /// set by a higher level guard). 01220 /// The default action is eDiscard. 01221 CDiagCollectGuard(EDiagSev print_severity); 01222 01223 /// Create diag collect guard with the given severities and action. 01224 /// The guard will not set print severity below the current diag 01225 /// post level (or print severity of a higher level guard). 01226 /// Collect severity should be equal or lower than the current 01227 /// diag post level or collect severity. 01228 /// The default action is eDiscard. 01229 CDiagCollectGuard(EDiagSev print_severity, 01230 EDiagSev collect_severity, 01231 EAction action = eDiscard); 01232 01233 /// Destroy the guard, return post level to the one set before the 01234 /// guard initialization. Depending on the currently set action 01235 /// print or discard the messages. 01236 /// On ePrint all collected messages are printed (if there is no 01237 /// higher level guard) and removed from the collection. 01238 /// On eDiscard the messages are silently discarded (only when the 01239 /// last of several nested guards is destroyed). 01240 ~CDiagCollectGuard(void); 01241 01242 /// Get current print severity 01243 EDiagSev GetPrintSeverity(void) const { return m_PrintSev; } 01244 /// Set new print severity. The new print severity can not be 01245 /// lower than the current one. 01246 void SetPrintSeverity(EDiagSev sev); 01247 01248 /// Get current collect severity 01249 EDiagSev GetCollectSeverity(void) const { return m_CollectSev; } 01250 /// Set new collect severity. The new collect severity can not be 01251 /// higher than the current one. 01252 void SetCollectSeverity(EDiagSev sev); 01253 01254 /// Get selected on-destroy action 01255 EAction GetAction(void) const { return m_Action; } 01256 /// Specify on-destroy action. 01257 void SetAction(EAction action) { m_Action = action; } 01258 01259 /// Release the guard. Perform the currently set action, stop collecting 01260 /// messages, reset severities set by this guard. 01261 void Release(void); 01262 01263 /// Release the guard. Perform the specified action, stop collecting 01264 /// messages, reset severities set by this guard. 01265 void Release(EAction action); 01266 01267 private: 01268 void x_Init(EDiagSev print_severity, 01269 EDiagSev collect_severity, 01270 EAction action); 01271 01272 EDiagSev m_PrintSev; 01273 EDiagSev m_CollectSev; 01274 EAction m_Action; 01275 }; 01276 01277 01278 /// Specify a string to prefix all subsequent error postings with. 01279 01280 extern void SetDiagPostPrefix(const char* prefix); 01281 01282 /// Push a string to the list of message prefixes. 01283 01284 extern void PushDiagPostPrefix(const char* prefix); 01285 01286 /// Pop a string from the list of message prefixes. 01287 01288 extern void PopDiagPostPrefix(void); 01289 01290 /// Get iteration number/request ID. 01291 01292 extern int GetDiagRequestId(void); 01293 01294 /// Set iteration number/request ID. 01295 01296 extern void SetDiagRequestId(int id); 01297 01298 01299 NCBI_DEPRECATED 01300 inline int GetFastCGIIteration(void) 01301 { 01302 return GetDiagRequestId(); 01303 } 01304 01305 01306 NCBI_DEPRECATED 01307 inline void SetFastCGIIteration(int id) 01308 { 01309 SetDiagRequestId(id); 01310 } 01311 01312 01313 ///////////////////////////////////////////////////////////////////////////// 01314 /// 01315 /// CDiagAutoPrefix -- 01316 /// 01317 /// Define the auxiliary class to temporarily add a prefix. 01318 01319 class CDiagAutoPrefix 01320 { 01321 public: 01322 /// Constructor. 01323 CDiagAutoPrefix(const string& prefix); 01324 01325 /// Constructor. 01326 CDiagAutoPrefix(const char* prefix); 01327 01328 /// Remove the prefix automagically, when the object gets out of scope. 01329 ~CDiagAutoPrefix(void); 01330 }; 01331 01332 01333 /// Diagnostic post severity level. 01334 /// 01335 /// The value of DIAG_POST_LEVEL can be a digital value (0-9) or 01336 /// string value from CDiagBuffer::sm_SeverityName[]. 01337 #define DIAG_POST_LEVEL "DIAG_POST_LEVEL" 01338 01339 /// Set the threshold severity for posting the messages. 01340 /// 01341 /// This function has effect only if: 01342 /// - Environment variable $DIAG_POST_LEVEL is not set, and 01343 /// - Registry value of DIAG_POST_LEVEL, section DEBUG is not set 01344 /// 01345 /// Another way to do filtering is to call SetDiagFilter 01346 /// 01347 /// @param post_sev 01348 /// Post only messages with severity greater or equal to "post_sev". 01349 /// 01350 /// Special case: eDiag_Trace -- print all messages and turn on the tracing. 01351 /// @return 01352 /// Return previous post-level. 01353 /// @sa SetDiagFilter(), SetDiagTrace() 01354 01355 extern EDiagSev SetDiagPostLevel(EDiagSev post_sev = eDiag_Error); 01356 01357 /// Compare two severities. 01358 /// @return 01359 /// The return value is negative if the first value is lower than 01360 /// the second one, positive if it's higher than the second one, 01361 /// 0 if the severities are equal. 01362 01363 extern int CompareDiagPostLevel(EDiagSev sev1, EDiagSev sev2); 01364 01365 /// Check if the specified severity is higher or equal to the currently 01366 /// selected post level and will be printed by LOG_POST/ERR_POST. 01367 01368 extern bool IsVisibleDiagPostLevel(EDiagSev sev); 01369 01370 /// Disable change the diagnostic post level. 01371 /// 01372 /// Consecutive using SetDiagPostLevel() will not have effect. 01373 01374 extern bool DisableDiagPostLevelChange(bool disable_change = true); 01375 01376 /// Sets and locks the level, combining the previous two calls. 01377 01378 extern void SetDiagFixedPostLevel(EDiagSev post_sev); 01379 01380 /// Set the "die" (abort) level for the program. 01381 /// 01382 /// Abort the application if severity is >= "die_sev". 01383 /// Throw an exception if die_sev is not in the range 01384 /// [eDiagSevMin..eDiag_Fatal]. 01385 /// @return 01386 /// Return previous die-level. 01387 01388 extern EDiagSev SetDiagDieLevel(EDiagSev die_sev = eDiag_Fatal); 01389 01390 /// Ignore the die level settings. Return previous setting. 01391 /// 01392 /// WARNING!!! -- not recommended for use unless you are real desperate: 01393 /// By passing TRUE to this function you can make your application 01394 /// never exit/abort regardless of the level set by SetDiagDieLevel(). 01395 /// But be warned this is usually a VERY BAD thing to do! 01396 /// -- because any library code counts on at least "eDiag_Fatal" to exit 01397 /// unconditionally, and thus what happens once "eDiag_Fatal" has been posted, 01398 /// is, in general, totally unpredictable! Therefore, use it on your own risk. 01399 01400 extern bool IgnoreDiagDieLevel(bool ignore); 01401 01402 /// Abort handler function type. 01403 typedef void (*FAbortHandler)(void); 01404 01405 /// Set/unset abort handler. 01406 /// 01407 /// If "func"==0 use default handler. 01408 01409 extern void SetAbortHandler(FAbortHandler func = 0); 01410 01411 /// Smart abort function. 01412 /// 01413 /// Processes user abort handler and does not popup assert windows 01414 /// if specified (environment variable DIAG_SILENT_ABORT is "Y" or "y"). 01415 01416 extern void Abort(void); 01417 01418 /// Diagnostic trace setting. 01419 #define DIAG_TRACE "DIAG_TRACE" 01420 01421 /// Which setting disables/enables posting of "eDiag_Trace" messages. 01422 /// 01423 /// By default, trace messages are disabled unless: 01424 /// - Environment variable $DIAG_TRACE is set (to any value), or 01425 /// - Registry value of DIAG_TRACE, section DEBUG is set (to any value) 01426 enum EDiagTrace { 01427 eDT_Default = 0, ///< Restores the default tracing context 01428 eDT_Disable, ///< Ignore messages of severity "eDiag_Trace" 01429 eDT_Enable ///< Enable messages of severity "eDiag_Trace" 01430 }; 01431 01432 01433 /// Set the diagnostic trace settings. 01434 01435 extern void SetDiagTrace(EDiagTrace how, EDiagTrace dflt = eDT_Default); 01436 01437 01438 01439 /// Forward declarations 01440 class CTime; 01441 01442 /// Internal structure to hold diag message string data. 01443 struct SDiagMessageData; 01444 01445 struct SDiagMessage; 01446 01447 /// Callback interface for stream parser. Called for every message read 01448 /// from the input stream. 01449 /// @sa SDiagMessage 01450 class INextDiagMessage 01451 { 01452 public: 01453 virtual void operator()(SDiagMessage& msg) = 0; 01454 virtual ~INextDiagMessage(void) {} 01455 }; 01456 01457 01458 ///////////////////////////////////////////////////////////////////////////// 01459 /// 01460 /// SDiagMessage -- 01461 /// 01462 /// Diagnostic message structure. 01463 /// 01464 /// Defines structure of the "data" message that is used with message handler 01465 /// function("func"), and destructor("cleanup"). 01466 /// The "func(..., data)" to be called when any instance of "CNcbiDiagBuffer" 01467 /// has a new diagnostic message completed and ready to post. 01468 /// "cleanup(data)" will be called whenever this hook gets replaced and 01469 /// on the program termination. 01470 /// NOTE 1: "func()", "cleanup()" and "g_SetDiagHandler()" calls are 01471 /// MT-protected, so that they would never be called simultaneously 01472 /// from different threads. 01473 /// NOTE 2: By default, the errors will be written to standard error stream. 01474 01475 struct SDiagMessage { 01476 typedef Uint8 TPID; ///< Process ID 01477 typedef Uint8 TTID; ///< Thread ID 01478 typedef Int8 TUID; ///< Unique process ID 01479 01480 /// Initalize SDiagMessage fields. 01481 SDiagMessage(EDiagSev severity, const char* buf, size_t len, 01482 const char* file = 0, size_t line = 0, 01483 TDiagPostFlags flags = eDPF_Default, const char* prefix = 0, 01484 int err_code = 0, int err_subcode = 0, 01485 const char* err_text = 0, 01486 const char* module = 0, 01487 const char* nclass = 0, 01488 const char* function = 0); 01489 01490 /// Copy constructor required to store the messages and flush them when 01491 /// the diagnostics setup is finished. 01492 SDiagMessage(const SDiagMessage& message); 01493 01494 /// Assignment of messages 01495 SDiagMessage& operator=(const SDiagMessage& message); 01496 01497 /// Parse a string back into SDiagMessage. Optional bool argument is 01498 /// set to true if the message was parsed successfully. 01499 SDiagMessage(const string& message, bool* result = 0); 01500 01501 ~SDiagMessage(void); 01502 01503 /// Parse the whole string into the message. 01504 /// Return true on success, false if parsing failed. 01505 bool ParseMessage(const string& message); 01506 01507 /// Stream parser. Reads messages from a stream and calls the callback 01508 /// for each message. 01509 static void ParseDiagStream(CNcbiIstream& in, 01510 INextDiagMessage& func); 01511 01512 /// Type of event to report 01513 enum EEventType { 01514 eEvent_Start, ///< Application start 01515 eEvent_Stop, ///< Application exit 01516 eEvent_Extra, ///< Other application events 01517 eEvent_RequestStart, ///< Start processing request 01518 eEvent_RequestStop ///< Finish processing request 01519 }; 01520 01521 static string GetEventName(EEventType event); 01522 01523 mutable EDiagSev m_Severity; ///< Severity level 01524 const char* m_Buffer; ///< Not guaranteed to be '\0'-terminated! 01525 size_t m_BufferLen; ///< Length of m_Buffer 01526 const char* m_File; ///< File name 01527 const char* m_Module; ///< Module name 01528 const char* m_Class; ///< Class name 01529 const char* m_Function; ///< Function name 01530 size_t m_Line; ///< Line number in file 01531 int m_ErrCode; ///< Error code 01532 int m_ErrSubCode; ///< Sub Error code 01533 TDiagPostFlags m_Flags; ///< Bitwise OR of "EDiagPostFlag" 01534 const char* m_Prefix; ///< Prefix string 01535 const char* m_ErrText; ///< Sometimes 'error' has no numeric code, 01536 ///< but can be represented as text 01537 TPID m_PID; ///< Process ID 01538 TTID m_TID; ///< Thread ID 01539 int m_ProcPost; ///< Number of the post in the process 01540 int m_ThrPost; ///< Number of the post in the thread 01541 int m_RequestId; ///< FastCGI iteration or request ID 01542 01543 /// If the severity is eDPF_AppLog, m_Event contains event type. 01544 EEventType m_Event; 01545 01546 typedef pair<string, string> TExtraArg; 01547 typedef vector<TExtraArg> TExtraArgs; 01548 01549 /// If event type is "extra", contains the list of arguments 01550 TExtraArgs m_ExtraArgs; 01551 /// Set to true if this is a typed extra message (the arguments include 01552 /// "NCBIEXTRATYPE=<extra-type>"). 01553 bool m_TypedExtra; 01554 01555 /// Convert extra arguments to string 01556 string FormatExtraMessage(void) const; 01557 01558 /// Get UID from current context or parsed from a string 01559 TUID GetUID(void) const; 01560 /// Get time and date - current or parsed. 01561 CTime GetTime(void) const; 01562 01563 /// Compose a message string in the standard format(see also "flags"): 01564 /// "<file>", line <line>: <severity>: [<prefix>] <message> [EOL] 01565 /// and put it to string "str", or write to an output stream "os". 01566 01567 /// Which write flags should be output in diagnostic message. 01568 enum EDiagWriteFlags { 01569 fNone = 0x0, ///< No flags 01570 fNoEndl = 0x01, ///< No end of line 01571 fNoPrefix = 0x02 ///< No std prefix 01572 }; 01573 01574 typedef int TDiagWriteFlags; /// Binary OR of "EDiagWriteFlags" 01575 01576 /// Write to string. 01577 void Write(string& str, TDiagWriteFlags flags = fNone) const; 01578 01579 /// Write to stream. 01580 CNcbiOstream& Write (CNcbiOstream& os, TDiagWriteFlags fl = fNone) const; 01581 01582 /// Access to strings stored in SDiagMessageData. 01583 const string& GetHost(void) const; 01584 const string& GetClient(void) const; 01585 const string& GetSession(void) const; 01586 const string& GetAppName(void) const; 01587 EDiagAppState GetAppState(void) const; 01588 01589 /// For compatibility x_Write selects old or new message formatting 01590 /// depending on DIAG_OLD_POST_FORMAT parameter. 01591 CNcbiOstream& x_Write(CNcbiOstream& os, TDiagWriteFlags fl = fNone) const; 01592 CNcbiOstream& x_OldWrite(CNcbiOstream& os, TDiagWriteFlags fl = fNone) const; 01593 CNcbiOstream& x_NewWrite(CNcbiOstream& os, TDiagWriteFlags fl = fNone) const; 01594 string x_GetModule(void) const; 01595 01596 private: 01597 // Parse extra args formatted as CGI query string. Do not check validity 01598 // of names and values. Split args by '&', split name/value by '=', do 01599 // URL-decoding. 01600 // If the string is not in the correct format (no '&' or '=') do not 01601 // parse it, return false. 01602 bool x_ParseExtraArgs(const string& str, size_t pos); 01603 01604 enum EFormatFlag { 01605 eFormat_Old, // Force old post format 01606 eFormat_New, // Force new post format 01607 eFormat_Auto // Get post format from CDiagContext, default 01608 }; 01609 void x_SetFormat(EFormatFlag fmt) const { m_Format = fmt; } 01610 bool x_IsSetOldFormat(void) const; 01611 friend class CDiagContext; 01612 01613 // Initialize data with the current values 01614 void x_InitData(void) const; 01615 // Save current context properties 01616 void x_SaveContextData(void) const; 01617 01618 mutable SDiagMessageData* m_Data; 01619 mutable EFormatFlag m_Format; 01620 }; 01621 01622 /// Insert message in output stream. 01623 inline CNcbiOstream& operator<< (CNcbiOstream& os, const SDiagMessage& mess) { 01624 return mess.Write(os); 01625 } 01626 01627 01628 01629 ///////////////////////////////////////////////////////////////////////////// 01630 /// 01631 /// CDiagContext -- 01632 /// 01633 /// NCBI diagnostic context. Storage for application-wide properties. 01634 01635 class CStopWatch; 01636 class CDiagHandler; 01637 class CNcbiRegistry; 01638 01639 /// Where to write the application's diagnostics to. 01640 enum EAppDiagStream { 01641 eDS_ToStdout, ///< To standard output stream 01642 eDS_ToStderr, ///< To standard error stream 01643 eDS_ToStdlog, ///< Try standard log file (app.name + ".log") in /log/ 01644 ///< and current directory, use stderr if both fail. 01645 eDS_ToMemory, ///< Keep in a temp.memory buffer, see FlushMessages() 01646 eDS_Disable, ///< Dont write it anywhere 01647 eDS_User, ///< Leave as was previously set (or not set) by user 01648 eDS_AppSpecific, ///< Call the application's SetupDiag_AppSpecific() 01649 ///< @deprecated 01650 eDS_Default, ///< Try standard log file (app.name + ".log") in /log/, 01651 ///< use stderr on failure. 01652 eDS_ToSyslog ///< To system log daemon 01653 }; 01654 01655 01656 /// Flags to control collecting messages and flushing them to the new 01657 /// destination when switching diag handlers. 01658 enum EDiagCollectMessages { 01659 eDCM_Init, ///< Start collecting messages (with limit), do nothing 01660 ///< if already initialized. 01661 eDCM_InitNoLimit, ///< Start collecting messages without limit (must stop 01662 ///< collecting later using eDCM_Flush or eDCM_Discard). 01663 eDCM_NoChange, ///< Continue collecting messages if already started. 01664 eDCM_Flush, ///< Flush the collected messages and stop collecting. 01665 eDCM_Discard ///< Discard the collected messages without flushing. 01666 }; 01667 01668 01669 /// Post nubmer increment flag for GetProcessPostNumber() and 01670 /// GetThreadPostNumber(). 01671 enum EPostNumberIncrement { 01672 ePostNumber_NoIncrement, ///< Get post number without incrementing it 01673 ePostNumber_Increment ///< Increment and return the new post number 01674 }; 01675 01676 01677 struct SRequestCtxWrapper; 01678 class CRequestContext; 01679 class CRequestRateControl; 01680 class CEncodedString; 01681 01682 01683 /// Thread local context data stored in TLS 01684 class CDiagContextThreadData 01685 { 01686 public: 01687 CDiagContextThreadData(void); 01688 ~CDiagContextThreadData(void); 01689 01690 /// Get current request context. 01691 CRequestContext& GetRequestContext(void); 01692 /// Set request context. If NULL, switches the current thread 01693 /// to its default request context. 01694 void SetRequestContext(CRequestContext* ctx); 01695 01696 /// CDiagContext properties 01697 typedef map<string, string> TProperties; 01698 enum EGetProperties { 01699 eProp_Get, ///< Do not create properties if not exist yet 01700 eProp_Create ///< Auto-create properties if not exist 01701 }; 01702 NCBI_DEPRECATED TProperties* GetProperties(EGetProperties flag); 01703 01704 /// Request id 01705 NCBI_DEPRECATED int GetRequestId(void); 01706 NCBI_DEPRECATED void SetRequestId(int id); 01707 NCBI_DEPRECATED void IncRequestId(void); 01708 01709 /// Get request timer, create if not exist yet 01710 NCBI_DEPRECATED CStopWatch* GetOrCreateStopWatch(void) { return NULL; } 01711 /// Get request timer or null 01712 NCBI_DEPRECATED CStopWatch* GetStopWatch(void) { return NULL; } 01713 /// Delete request timer 01714 NCBI_DEPRECATED void ResetStopWatch(void) {} 01715 01716 /// Diag buffer 01717 CDiagBuffer& GetDiagBuffer(void) { return *m_DiagBuffer; } 01718 01719 /// Get diag context data for the current thread 01720 static CDiagContextThreadData& GetThreadData(void); 01721 01722 /// Thread ID 01723 typedef Uint8 TTID; 01724 01725 /// Get cached thread ID 01726 TTID GetTID(void) const { return m_TID; } 01727 01728 /// Get thread post number 01729 int GetThreadPostNumber(EPostNumberIncrement inc); 01730 01731 void AddCollectGuard(CDiagCollectGuard* guard); 01732 void RemoveCollectGuard(CDiagCollectGuard* guard); 01733 CDiagCollectGuard* GetCollectGuard(void); 01734 01735 void CollectDiagMessage(const SDiagMessage& mess); 01736 01737 private: 01738 CDiagContextThreadData(const CDiagContextThreadData&); 01739 CDiagContextThreadData& operator=(const CDiagContextThreadData&); 01740 01741 // Guards override the global post level and define severity 01742 // for collecting messages. 01743 typedef list<CDiagCollectGuard*> TCollectGuards; 01744 01745 // Collected diag messages 01746 typedef list<SDiagMessage> TDiagCollection; 01747 01748 auto_ptr<TProperties> m_Properties; // Per-thread properties 01749 auto_ptr<CDiagBuffer> m_DiagBuffer; // Thread's diag buffer 01750 TTID m_TID; // Cached thread ID 01751 int m_ThreadPostNumber; // Number of posted messages 01752 TCollectGuards m_CollectGuards; 01753 TDiagCollection m_DiagCollection; 01754 size_t m_DiagCollectionSize; // cached size of m_DiagCollection 01755 auto_ptr<SRequestCtxWrapper> m_RequestCtx; // Request context 01756 auto_ptr<SRequestCtxWrapper> m_DefaultRequestCtx; // Default request context 01757 }; 01758 01759 01760 /// Temporary object for holding extra message arguments. Prints all 01761 /// of the arguments on destruction. 01762 class CDiagContext_Extra 01763 { 01764 public: 01765 /// Prints all arguments as "name1=value1&name2=value2...". 01766 ~CDiagContext_Extra(void); 01767 /// The method does not print the argument, but adds it to the string. 01768 /// Name must contain only alphanumeric chars or '_'. 01769 /// Value is URL-encoded before printing. 01770 CDiagContext_Extra& Print(const string& name, const string& value); 01771 01772 /// Copying the object will prevent printing it on destruction. 01773 /// The new copy should take care of printing. 01774 CDiagContext_Extra(const CDiagContext_Extra& args); 01775 CDiagContext_Extra& operator=(const CDiagContext_Extra& args); 01776 01777 /// Print the message and reset object 01778 void Flush(void); 01779 01780 /// Set extra message type. 01781 CDiagContext_Extra& SetType(const string& type); 01782 01783 private: 01784 void x_Release(void); 01785 01786 // Can be created only by CDiagContext. 01787 CDiagContext_Extra(SDiagMessage::EEventType event_type); 01788 friend class CDiagContext; 01789 01790 typedef SDiagMessage::TExtraArg TExtraArg; 01791 typedef SDiagMessage::TExtraArgs TExtraArgs; 01792 01793 SDiagMessage::EEventType m_EventType; 01794 TExtraArgs* m_Args; 01795 int* m_Counter; 01796 bool m_Typed; 01797 }; 01798 01799 01800 class CDiagContext 01801 { 01802 public: 01803 CDiagContext(void); 01804 ~CDiagContext(void); 01805 01806 typedef Uint8 TPID; 01807 // Get cached PID (read real PID if not cached yet). 01808 static TPID GetPID(void); 01809 // Reset PID cache (e.g. after fork). 01810 static void UpdatePID(void); 01811 01812 typedef SDiagMessage::TUID TUID; 01813 01814 /// Return (create if not created yet) unique diagnostic ID. 01815 TUID GetUID(void) const; 01816 /// Return string representation of UID. 01817 /// If the argument UID is 0, use the one from the diag context. 01818 string GetStringUID(TUID uid = 0) const; 01819 /// Take the source UID and replace its timestamp part with the 01820 /// current time. 01821 /// If the source UID is 0, use the one from the diag context. 01822 TUID UpdateUID(TUID uid = 0) const; 01823 01824 /// Create global unique request id. 01825 string GetNextHitID(void) const; 01826 /// Deprecated version of HID generator. 01827 NCBI_DEPRECATED 01828 string GetGlobalRequestId(void) const { return GetNextHitID(); } 01829 01830 /// Shortcut to 01831 /// CDiagContextThreadData::GetThreadData().GetRequestContext() 01832 static CRequestContext& GetRequestContext(void); 01833 /// Shortcut to 01834 /// CDiagContextThreadData::GetThreadData().SetRequestContext() 01835 static void SetRequestContext(CRequestContext* ctx); 01836 01837 /// Set AutoWrite flag. If set, each property is posted to the current 01838 /// app-log stream when a new value is set. 01839 /// @deprecated 01840 NCBI_DEPRECATED 01841 void SetAutoWrite(bool value); 01842 01843 /// Property visibility flag. 01844 /// @deprecated 01845 enum EPropertyMode { 01846 eProp_Default, ///< Auto-mode for known properties, local for others 01847 eProp_Global, ///< The property is global for the application 01848 eProp_Thread ///< The property has separate value in each thread 01849 }; 01850 01851 /// Set application context property by name. 01852 /// Write property to the log if AutoPrint flag is set. 01853 /// Property mode defines if the property is a global or a 01854 /// per-thread one. By default unknown properties are set as 01855 /// thread-local. 01856 /// @deprecated 01857 NCBI_DEPRECATED 01858 void SetProperty(const string& name, 01859 const string& value, 01860 EPropertyMode mode = eProp_Default); 01861 01862 /// Get application context property by name, return empty string if the 01863 /// property is not set. If mode is eProp_Default and the property is 01864 /// not a known one, check thread-local properties first. 01865 /// @deprecated 01866 NCBI_DEPRECATED 01867 string GetProperty(const string& name, 01868 EPropertyMode mode = eProp_Default) const; 01869 01870 /// Delete a property by name. If mode is eProp_Default and the property 01871 /// is not a known one, check thread-local properties first. 01872 /// @deprecated 01873 NCBI_DEPRECATED 01874 void DeleteProperty(const string& name, 01875 EPropertyMode mode = eProp_Default); 01876 01877 /// Forced dump of all set properties. 01878 /// @deprecated 01879 NCBI_DEPRECATED 01880 void PrintProperties(void); 01881 01882 /// Global properties 01883 static const char* kProperty_UserName; 01884 static const char* kProperty_HostName; 01885 static const char* kProperty_HostIP; 01886 static const char* kProperty_AppName; 01887 static const char* kProperty_ExitSig; 01888 static const char* kProperty_ExitCode; 01889 /// Per-thread properties 01890 static const char* kProperty_AppState; 01891 static const char* kProperty_ClientIP; 01892 static const char* kProperty_SessionID; 01893 static const char* kProperty_ReqStatus; 01894 static const char* kProperty_ReqTime; 01895 static const char* kProperty_BytesRd; 01896 static const char* kProperty_BytesWr; 01897 01898 /// Print start/stop etc. message. If the following values are set as 01899 /// properties, they will be dumped before the message: 01900 /// host | host_ip_addr 01901 /// client_ip 01902 /// session_id 01903 /// app_name 01904 /// All messages have the following prefix: 01905 /// PID/TID/ITER UID TIME HOST CLIENT SESSION_ID APP_NAME 01906 /// Depending on its type, a message can be prefixed with the following 01907 /// properties if they are set: 01908 /// start 01909 /// stop [SIG] [EXIT_CODE] ELAPSED_TIME 01910 /// extra 01911 /// request-start 01912 /// request-stop [STATUS] [REQ_ELAPSED_TIME] [BYTES_RD] [BYTES_WR] 01913 void PrintStart(const string& message); 01914 01915 /// Print exit message. 01916 void PrintStop(void); 01917 01918 /// Print extra message in plain text format. 01919 /// This method is deprecated and should be replaced by a call to 01920 /// Extra() method and one or more calls to CDiagContext_Extra::Print(). 01921 NCBI_DEPRECATED void PrintExtra(const string& message); 01922 01923 /// Create a temporary CDiagContext_Extra object. The object will print 01924 /// arguments automatically from destructor. Can be used like: 01925 /// Extra().Print(name1, val1).Print(name2, val2); 01926 CDiagContext_Extra Extra(void) 01927 { 01928 return CDiagContext_Extra(SDiagMessage::eEvent_Extra); 01929 } 01930 01931 /// Print request start message (for request-driven applications) 01932 void PrintRequestStart(const string& message); 01933 /// Create a temporary CDiagContext_Extra object. The object will print 01934 /// arguments automatically from destructor. Can be used like: 01935 /// PrintRequestStart().Print(name1, val1).Print(name2, val2); 01936 CDiagContext_Extra PrintRequestStart(void) 01937 { 01938 return CDiagContext_Extra(SDiagMessage::eEvent_RequestStart); 01939 } 01940 01941 /// Print request stop message (for request-driven applications) 01942 void PrintRequestStop(void); 01943 01944 /// Always returns global application state. 01945 EDiagAppState GetGlobalAppState(void) const; 01946 /// Set global application state. 01947 /// Do not change state of the current thread. 01948 void SetGlobalAppState(EDiagAppState state); 01949 /// Return application state for the current thread if it's set. 01950 /// If not set, return global application state. This is a shortcut 01951 /// to the current request context's GetAppState(). 01952 EDiagAppState GetAppState(void) const; 01953 /// Set application state. Application state is set globally and the 01954 /// thread's state is reset (for the current thread only). 01955 /// Request states are set for the current thread (request context) only. 01956 void SetAppState(EDiagAppState state); 01957 /// The 'mode' flag is deprecated. Use CRequestContext::SetAppState() for 01958 /// per-thread/per-request state. 01959 NCBI_DEPRECATED 01960 void SetAppState(EDiagAppState state, EPropertyMode mode); 01961 01962 /// Check old/new format flag (for compatibility only) 01963 static bool IsSetOldPostFormat(void); 01964 /// Set old/new format flag 01965 static void SetOldPostFormat(bool value); 01966 01967 /// Check if system TID is printed instead of CThread::GetSelf() 01968 static bool IsUsingSystemThreadId(void); 01969 /// Switch printing system TID (rather than CThread::GetSelf()) on/off 01970 static void UseSystemThreadId(bool value = true); 01971 01972 /// Get username 01973 const string& GetUsername(void) const; 01974 /// Set username 01975 /// @sa SetDiagUserAndHost 01976 void SetUsername(const string& username); 01977 01978 /// Get host name. The order is: cached hostname, cached hostIP, 01979 /// uname or COMPUTERNAME, SERVER_ADDR, empty string. 01980 const string& GetHost(void) const; 01981 /// URL-encoded version of GetHost() 01982 const string& GetEncodedHost(void) const; 01983 01984 /// Get cached hostname - do not try to detect host name as Getost() does. 01985 const string& GetHostname(void) const; 01986 /// Get URL-encoded hostname 01987 const string& GetEncodedHostname(void) const; 01988 /// Set hostname 01989 /// @sa SetDiagUserAndHost 01990 void SetHostname(const string& hostname); 01991 01992 /// Get host IP address 01993 const string& GetHostIP(void) const { return m_HostIP; } 01994 /// Set host IP address 01995 void SetHostIP(const string& ip); 01996 01997 /// Get application name 01998 const string& GetAppName(void) const; 01999 /// Get URL-encoded application name 02000 const string& GetEncodedAppName(void) const; 02001 /// Set application name 02002 void SetAppName(const string& app_name); 02003 02004 /// Get exit code 02005 int GetExitCode(void) const { return m_ExitCode; } 02006 /// Set exit code 02007 void SetExitCode(int exit_code) { m_ExitCode = exit_code; } 02008 02009 /// Get exit signal 02010 int GetExitSignal(void) const { return m_ExitSig; } 02011 /// Set exit signal 02012 void SetExitSignal(int exit_sig) { m_ExitSig = exit_sig; } 02013 02014 /// Write standard prefix to the stream. Use values from the message 02015 /// (PID/TID/RID etc.). 02016 void WriteStdPrefix(CNcbiOstream& ostr, 02017 const SDiagMessage& msg) const; 02018 02019 /// Start collecting all messages (the collected messages can be flushed 02020 /// to a new destination later). Stop collecting messages when max_size 02021 /// is reached. 02022 void InitMessages(size_t max_size = 100); 02023 /// Save new message 02024 void PushMessage(const SDiagMessage& message); 02025 /// Flush the collected messages to the current diag handler. 02026 /// Does not clear the collected messages. 02027 void FlushMessages(CDiagHandler& handler); 02028 /// Discard the collected messages without printing them. 02029 void DiscardMessages(void); 02030 /// Check if message collecting is on 02031 bool IsCollectingMessages(void) const { return m_Messages.get() != 0; } 02032 02033 /// Get log file truncation flag 02034 static bool GetLogTruncate(void); 02035 /// Set log file truncation flag 02036 static void SetLogTruncate(bool value); 02037 02038 /// Enable creating log files in /log directory. The function has no 02039 /// effect if called after final SetupDiag() by AppMain(). Otherwise 02040 /// it will try to switch logging to /log/fallback/UNKNOWN.log until 02041 /// the real log name is known. 02042 static void SetUseRootLog(void); 02043 02044 /// Application-wide diagnostics setup. Attempts to create log files 02045 /// or diag streams according to the 'ds' flag. If 'config' is set, 02046 /// gets name of the log file from the registry. 02047 static void SetupDiag(EAppDiagStream ds = eDS_Default, 02048 CNcbiRegistry* config = NULL, 02049 EDiagCollectMessages collect = eDCM_NoChange); 02050 02051 /// Return process post number (incrementing depends on the flag). 02052 static int GetProcessPostNumber(EPostNumberIncrement inc); 02053 02054 /// Type of logging rate limit 02055 enum ELogRate_Type { 02056 eLogRate_App, ///< Application log 02057 eLogRate_Err, ///< Error log 02058 eLogRate_Trace ///< Trace log 02059 }; 02060 02061 /// Logging rate control - max number of messages per period. 02062 unsigned int GetLogRate_Limit(ELogRate_Type type) const; 02063 void SetLogRate_Limit(ELogRate_Type type, unsigned int limit); 02064 02065 /// Logging rate control - the messages control period, seconds. 02066 unsigned int GetLogRate_Period(ELogRate_Type type) const; 02067 void SetLogRate_Period(ELogRate_Type type, unsigned int period); 02068 02069 /// Internal function, should be used only by CNcbiApplication. 02070 static void x_FinalizeSetupDiag(void); 02071 02072 private: 02073 CDiagContext(const CDiagContext&); 02074 CDiagContext& operator=(const CDiagContext&); 02075 02076 // Initialize UID 02077 void x_CreateUID(void) const; 02078 // Write message to the log using current handler 02079 void x_PrintMessage(SDiagMessage::EEventType event, 02080 const string& message); 02081 // Start request or report error if one is already running 02082 static void x_StartRequest(void); 02083 02084 typedef map<string, string> TProperties; 02085 friend class CDiagContext_Extra; 02086 02087 // Reset logging rates to the values stored in CParam-s 02088 void ResetLogRates(void); 02089 02090 // Check message logging rate 02091 bool ApproveMessage(SDiagMessage& msg, bool* show_warning); 02092 02093 static void sx_ThreadDataTlsCleanup(CDiagContextThreadData* value, 02094 void* cleanup_data); 02095 friend class CDiagContextThreadData; 02096 02097 friend class CDiagBuffer; 02098 02099 // Saved messages to be flushed after setting up log files 02100 typedef list<SDiagMessage> TMessages; 02101 02102 // Cached process ID 02103 static TPID sm_PID; 02104 02105 mutable TUID m_UID; 02106 mutable auto_ptr<CEncodedString> m_Host; 02107 string m_HostIP; 02108 auto_ptr<CEncodedString> m_Username; 02109 auto_ptr<CEncodedString> m_AppName; 02110 int m_ExitCode; 02111 int m_ExitSig; 02112 EDiagAppState m_AppState; 02113 TProperties m_Properties; 02114 auto_ptr<CStopWatch> m_StopWatch; 02115 auto_ptr<TMessages> m_Messages; 02116 size_t m_MaxMessages; 02117 static CDiagContext* sm_Instance; 02118 02119 // Rate control 02120 auto_ptr<CRequestRateControl> m_AppLogRC; 02121 auto_ptr<CRequestRateControl> m_ErrLogRC; 02122 auto_ptr<CRequestRateControl> m_TraceLogRC; 02123 bool m_AppLogSuspended; 02124 bool m_ErrLogSuspended; 02125 bool m_TraceLogSuspended; 02126 }; 02127 02128 02129 /// Get diag context instance 02130 CDiagContext& GetDiagContext(void); 02131 02132 02133 ///////////////////////////////////////////////////////////////////////////// 02134 /// 02135 /// CDiagHandler -- 02136 /// 02137 /// Base diagnostic handler class. 02138 02139 class CDiagHandler 02140 { 02141 public: 02142 /// Destructor. 02143 virtual ~CDiagHandler(void) {} 02144 02145 /// Post message to handler. 02146 virtual void Post(const SDiagMessage& mess) = 0; 02147 02148 /// Get current diag posts destination 02149 virtual string GetLogName(void); 02150 02151 enum EReopenFlags { 02152 fTruncate = 0x01, ///< Truncate file to zero size 02153 fCheck = 0x02, ///< Reopen only if necessary 02154 fDefault = 0 ///< Default reopen flags: 02155 ///< - no truncation 02156 ///< - do not check if necessary 02157 }; 02158 typedef int TReopenFlags; 02159 02160 /// Reopen file to enable log rotation. 02161 virtual void Reopen(TReopenFlags /*flags*/) {} 02162 }; 02163 02164 /// Diagnostic handler function type. 02165 typedef void (*FDiagHandler)(const SDiagMessage& mess); 02166 02167 /// Diagnostic cleanup function type. 02168 typedef void (*FDiagCleanup)(void* data); 02169 02170 /// Set the diagnostic handler using the specified diagnostic handler class. 02171 02172 extern void SetDiagHandler(CDiagHandler* handler, 02173 bool can_delete = true); 02174 02175 /// Get the currently set diagnostic handler class. 02176 02177 extern CDiagHandler* GetDiagHandler(bool take_ownership = false); 02178 02179 /// Set the diagnostic handler using the specified diagnostic handler 02180 /// and cleanup functions. 02181 02182 extern void SetDiagHandler(FDiagHandler func, 02183 void* data, 02184 FDiagCleanup cleanup); 02185 02186 /// Check if diagnostic handler is set. 02187 /// 02188 /// @return 02189 /// Return TRUE if user has ever set (or unset) diag. handler. 02190 02191 extern bool IsSetDiagHandler(void); 02192 02193 02194 /// Ask diagnostic handler to reopen log files if necessary. 02195 02196 extern void DiagHandler_Reopen(void); 02197 02198 02199 ///////////////////////////////////////////////////////////////////////////// 02200 // 02201 // Diagnostic Filter Functionality 02202 // 02203 02204 /// Diag severity types to put the filter on 02205 /// 02206 /// @sa SetDiagFilter 02207 enum EDiagFilter { 02208 eDiagFilter_Trace, ///< for TRACEs only 02209 eDiagFilter_Post, ///< for all non-TRACE, non-FATAL 02210 eDiagFilter_All ///< for all non-FATAL 02211 }; 02212 02213 02214 /// Set diagnostic filter 02215 /// 02216 /// Diagnostic filter acts as a second level filtering mechanism 02217 /// (the primary established by global error post level) 02218 /// @sa SetDiagPostLevel 02219 /// 02220 /// 02221 /// @param what 02222 /// Filter is set for 02223 /// @param filter_str 02224 /// Filter string 02225 02226 extern void SetDiagFilter(EDiagFilter what, const char* filter_str); 02227 02228 02229 ///////////////////////////////////////////////////////////////////////////// 02230 /// 02231 /// CStreamDiagHandler_Base -- 02232 /// 02233 /// Base class for stream and file based handlers 02234 02235 class CStreamDiagHandler_Base : public CDiagHandler 02236 { 02237 public: 02238 CStreamDiagHandler_Base(void); 02239 02240 virtual string GetLogName(void); 02241 virtual CNcbiOstream* GetStream(void) { return 0; } 02242 02243 protected: 02244 void SetLogName(const string& log_name) { m_LogName = log_name; } 02245 02246 private: 02247 string m_LogName; 02248 }; 02249 02250 02251 ///////////////////////////////////////////////////////////////////////////// 02252 /// 02253 /// CStreamDiagHandler -- 02254 /// 02255 /// Specialization of "CDiagHandler" for the stream-based diagnostics. 02256 02257 class CStreamDiagHandler : public CStreamDiagHandler_Base 02258 { 02259 public: 02260 /// Constructor. 02261 /// 02262 /// This does *not* own the stream; users will need to clean it up 02263 /// themselves if appropriate. 02264 /// @param os 02265 /// Output stream. 02266 /// @param quick_flush 02267 /// Do stream flush after every message. 02268 CStreamDiagHandler(CNcbiOstream* os, 02269 bool quick_flush = true, 02270 const string& stream_name = ""); 02271 02272 /// Post message to the handler. 02273 virtual void Post(const SDiagMessage& mess); 02274 virtual CNcbiOstream* GetStream(void) { return m_Stream; } 02275 02276 protected: 02277 CNcbiOstream* m_Stream; ///< Diagnostic stream 02278 02279 private: 02280 bool m_QuickFlush; ///< Quick flush of stream flag 02281 }; 02282 02283 02284 ///////////////////////////////////////////////////////////////////////////// 02285 /// 02286 /// CFileHandleDiagHandler -- 02287 /// 02288 /// Specialization of "CDiagHandler" for the file-handle based diagnostics. 02289 /// Writes messages using system write rather than stream to make the 02290 /// operation really atomic. Re-opens file periodically to make rotation 02291 /// possible. 02292 02293 class CFileHandleDiagHandler : public CStreamDiagHandler_Base 02294 { 02295 public: 02296 /// Constructor. 02297 /// 02298 /// Open file handle. 02299 /// themselves if appropriate. 02300 /// @param fname 02301 /// Output file name. 02302 CFileHandleDiagHandler(const string& fname); 02303 /// Close file handle 02304 ~CFileHandleDiagHandler(void); 02305 02306 /// Post message to the handler. 02307 virtual void Post(const SDiagMessage& mess); 02308 02309 bool Valid(void) { return m_Handle != -1; } 02310 02311 // Reopen file to enable log rotation. 02312 virtual void Reopen(TReopenFlags flags); 02313 02314 private: 02315 int m_Handle; ///< File handle 02316 CStopWatch* m_ReopenTimer; 02317 02318 /// Save messages if the handle is unavailable 02319 typedef list<SDiagMessage> TMessages; 02320 auto_ptr<TMessages> m_Messages; 02321 }; 02322 02323 02324 ///////////////////////////////////////////////////////////////////////////// 02325 /// 02326 /// CFileDiagHandler -- 02327 /// 02328 /// Specialization of "CDiagHandler" for the file-based diagnostics. 02329 /// Splits output into three files: .err (severity higher than the 02330 /// threshold), .trace (severity below the threshold) and .log 02331 /// (application access log). Re-opens the files periodically 02332 /// to allow safe log rotation. 02333 02334 /// Type of file for the output 02335 enum EDiagFileType 02336 { 02337 eDiagFile_Err, ///< Error log file 02338 eDiagFile_Log, ///< Access log file 02339 eDiagFile_Trace, ///< Trace log file 02340 eDiagFile_All ///< All log files 02341 }; 02342 02343 class CFileDiagHandler : public CStreamDiagHandler_Base 02344 { 02345 public: 02346 /// Constructor. initializes log file(s) with the arguments. 02347 /// @sa SetLogFile 02348 CFileDiagHandler(void); 02349 ~CFileDiagHandler(void); 02350 02351 /// Post message to the handler. Info and Trace messages are sent 02352 /// to file_name.trace file, all others go to file_name.err file. 02353 /// Application access messages go to file_name.log file. 02354 virtual void Post(const SDiagMessage& mess); 02355 02356 /// Set new log file. 02357 /// 02358 /// @param file_name 02359 /// File name. If file_type is eDiagFile_All, the output will be written 02360 /// to file_name.(err|log|trace). Otherwise the filename is used as-is. 02361 /// Special filenames are: 02362 /// "" - disable diag messages; 02363 /// "-" - print to stderr 02364 /// "/dev/null" - never add .(err|log|trace) to the name. 02365 /// @param file_type 02366 /// Type of log file to set - error, trace or application log. 02367 /// @param quick_flush 02368 /// Do stream flush after every message. 02369 bool SetLogFile(const string& file_name, 02370 EDiagFileType file_type, 02371 bool quick_flush); 02372 02373 /// Get current log file name. If file_type is eDiagFile_All, always 02374 /// returns empty string. 02375 string GetLogFile(EDiagFileType file_type) const; 02376 02377 /// Get current log stream. Return NULL if the selected destination 02378 /// is not a stream. 02379 CNcbiOstream* GetLogStream(EDiagFileType file_type); 02380 02381 // Reopen all files to enable log rotation. 02382 virtual void Reopen(TReopenFlags flags); 02383 02384 // Set the selected sub-handler directly with the given ownership. 02385 void SetSubHandler(CStreamDiagHandler_Base* handler, 02386 EDiagFileType file_type, 02387 bool own); 02388 02389 /// Change ownership for the given handler if it's currently installed. 02390 void SetOwnership(CStreamDiagHandler_Base* handler, bool own); 02391 02392 private: 02393 // Check if the object is owned and if it's used as more than one handler, 02394 // update ownership or delete the handler if necessary. 02395 void x_ResetHandler(CStreamDiagHandler_Base** ptr, bool* owned); 02396 // Set the selected member to the handler, make sure only one 02397 // owhnership flag is set for the handler. 02398 void x_SetHandler(CStreamDiagHandler_Base** member, 02399 bool* own_member, 02400 CStreamDiagHandler_Base* handler, 02401 bool own); 02402 02403 CStreamDiagHandler_Base* m_Err; 02404 bool m_OwnErr; 02405 CStreamDiagHandler_Base* m_Log; 02406 bool m_OwnLog; 02407 CStreamDiagHandler_Base* m_Trace; 02408 bool m_OwnTrace; 02409 CStopWatch* m_ReopenTimer; 02410 }; 02411 02412 02413 /// Output diagnostics using both old and new style handlers. 02414 NCBI_DEPRECATED 02415 extern void SetDoubleDiagHandler(void); ///< @deprecated 02416 02417 02418 /// Set diagnostic stream. 02419 /// 02420 /// Error diagnostics are written to output stream "os". 02421 /// This uses the SetDiagHandler() functionality. 02422 02423 extern void SetDiagStream 02424 (CNcbiOstream* os, 02425 bool quick_flush = true,///< Do stream flush after every message 02426 FDiagCleanup cleanup = 0, ///< Call "cleanup(cleanup_data)" if diag. 02427 void* cleanup_data = 0, ///< Stream is changed (see SetDiagHandler) 02428 const string& stream_name = "STREAM" ///< Stream name (e.g. STDERR, file.log) 02429 ); 02430 02431 // Return TRUE if "os" is the current diag. stream. 02432 02433 extern bool IsDiagStream(const CNcbiOstream* os); 02434 02435 /// Get current diagnostic stream (if it was set by SetDiagStream) or NULL. 02436 02437 extern CNcbiOstream* GetDiagStream(void); 02438 02439 /// Split log files flag. If set, the output is sent to different 02440 /// log files depending on the severity level. 02441 extern void SetSplitLogFile(bool value = true); 02442 /// Get split log files flag. 02443 extern bool GetSplitLogFile(void); 02444 02445 /// Set log files. 02446 /// Send output to file_name or to file_name.(err|log|trace) depending 02447 /// on the split log file flag and file_type. If a single file type 02448 /// is selected, other types remain the same or are switched to 02449 /// stderr if their files have not been assigned yet. 02450 /// If split log flag is off, any file type except eDiagFile_All 02451 /// will be ignored. 02452 /// If the file_name contains one of the extensions .log, .err or .trace 02453 /// and the file type is eDiagFile_All, the extension will be removed 02454 /// before adding the new one. 02455 /// Return true on success, false if the file could not be open. 02456 02457 extern bool SetLogFile(const string& file_name, 02458 EDiagFileType file_type = eDiagFile_All, 02459 bool quick_flush = true); 02460 02461 /// Get log file name for the given log type. Return empty string for 02462 /// eDiagFile_All or if the log file handler is not installed. 02463 02464 extern string GetLogFile(EDiagFileType file_type); 02465 02466 /// Get log file name or diag handler name. 02467 02468 extern string GetLogFile(void); 02469 02470 02471 ///////////////////////////////////////////////////////////////////////////// 02472 /// 02473 /// CDiagFactory -- 02474 /// 02475 /// Diagnostic handler factory. 02476 02477 class CDiagFactory 02478 { 02479 public: 02480 virtual ~CDiagFactory() { } 02481 /// Factory method interface. 02482 virtual CDiagHandler* New(const string& s) = 0; 02483 }; 02484 02485 02486 02487 ///////////////////////////////////////////////////////////////////////////// 02488 /// 02489 /// CDiagRestorer -- 02490 /// 02491 /// Auxiliary class to limit the duration of changes to diagnostic settings. 02492 02493 class CDiagRestorer 02494 { 02495 public: 02496 CDiagRestorer (void); ///< Captures current settings 02497 ~CDiagRestorer(void); ///< Restores captured settings 02498 private: 02499 /// Private new operator. 02500 /// 02501 /// Prohibit dynamic allocation because there's no good reason to allow 02502 /// it, and out-of-order destruction is problematic. 02503 void* operator new (size_t) { throw runtime_error("forbidden"); } 02504 02505 /// Private new[] operator. 02506 /// 02507 /// Prohibit dynamic allocation because there's no good reason to allow 02508 /// it, and out-of-order destruction is problematic. 02509 void* operator new[] (size_t) { throw runtime_error("forbidden"); } 02510 02511 /// Private delete operator. 02512 /// 02513 /// Prohibit dynamic deallocation (and allocation) because there's no 02514 /// good reason to allow it, and out-of-order destruction is problematic. 02515 void operator delete (void*) { throw runtime_error("forbidden"); } 02516 02517 /// Private delete[] operator. 02518 /// 02519 /// Prohibit dynamic deallocation (and allocation) because there's no 02520 /// good reason to allow it, and out-of-order destruction is problematic. 02521 void operator delete[] (void*) { throw runtime_error("forbidden"); } 02522 02523 string m_PostPrefix; ///< Message prefix 02524 list<string> m_PrefixList; ///< List of prefixs 02525 TDiagPostFlags m_PostFlags; ///< Post flags 02526 EDiagSev m_PostSeverity; ///< Post severity 02527 EDiagSevChange m_PostSeverityChange; ///< Severity change 02528 bool m_IgnoreToDie; ///< Ignore to die on die sev 02529 EDiagSev m_DieSeverity; ///< Die level severity 02530 EDiagTrace m_TraceDefault; ///< Default trace setting 02531 bool m_TraceEnabled; ///< Trace enabled? 02532 CDiagHandler* m_Handler; ///< Class handler 02533 bool m_CanDeleteHandler; ///< Can handler be deleted? 02534 CDiagErrCodeInfo* m_ErrCodeInfo; ///< Error code information 02535 bool m_CanDeleteErrCodeInfo; ///< Can delete err code info? 02536 }; 02537 02538 02539 02540 ///////////////////////////////////////////////////////////////////////////// 02541 /// 02542 /// SDiagErrCodeDescription -- 02543 /// 02544 /// Structure used to store the errors code and subcode description. 02545 02546 struct SDiagErrCodeDescription { 02547 /// Constructor. 02548 SDiagErrCodeDescription(void); 02549 02550 /// Destructor. 02551 SDiagErrCodeDescription(const string& message, ///< Message 02552 const string& explanation, ///< Explanation of msg. 02553 int severity = -1 02554 ///< Do not override 02555 ///< if set to -1 02556 ) 02557 : m_Message(message), 02558 m_Explanation(explanation), 02559 m_Severity(severity) 02560 { 02561 return; 02562 } 02563 02564 public: 02565 string m_Message; ///< Error message (short) 02566 string m_Explanation; ///< Error message (with detailed explanation) 02567 int m_Severity; 02568 ///< Message severity (if less that 0, then use 02569 ///< current diagnostic severity level) 02570 }; 02571 02572 02573 02574 ///////////////////////////////////////////////////////////////////////////// 02575 /// 02576 /// CDiagErrCodeInfo -- 02577 /// 02578 /// Stores mapping of error codes and their descriptions. 02579 02580 class CDiagErrCodeInfo 02581 { 02582 public: 02583 /// Constructor. 02584 CDiagErrCodeInfo(void); 02585 02586 /// Constructor -- can throw runtime_error. 02587 CDiagErrCodeInfo(const string& file_name); 02588 02589 /// Constructor -- can throw runtime_error. 02590 CDiagErrCodeInfo(CNcbiIstream& is); 02591 02592 /// Destructor. 02593 ~CDiagErrCodeInfo(void); 02594 02595 /// Read error description from specified file. 02596 /// 02597 /// Read error descriptions from the specified file, 02598 /// store it in memory. 02599 bool Read(const string& file_name); 02600 02601 /// Read error description from specified stream. 02602 /// 02603 /// Read error descriptions from the specified stream, 02604 /// store it in memory. 02605 bool Read(CNcbiIstream& is); 02606 02607 /// Delete all stored error descriptions from memory. 02608 void Clear(void); 02609 02610 /// Get description for specified error code. 02611 /// 02612 /// Get description message for the error by its code. 02613 /// @return 02614 /// TRUE if error description exists for this code; 02615 /// return FALSE otherwise. 02616 bool GetDescription(const ErrCode& err_code, 02617 SDiagErrCodeDescription* description) const; 02618 02619 /// Set error description for specified error code. 02620 /// 02621 /// If description for this code already exist, then it 02622 /// will be overwritten. 02623 void SetDescription(const ErrCode& err_code, 02624 const SDiagErrCodeDescription& description); 02625 02626 /// Check if error description exists. 02627 /// 02628 /// Return TRUE if description for specified error code exists, 02629 /// otherwise return FALSE. 02630 bool HaveDescription(const ErrCode& err_code) const; 02631 02632 private: 02633 02634 /// Define map for error messages. 02635 typedef map<ErrCode, SDiagErrCodeDescription> TInfo; 02636 02637 /// Map storing error codes and descriptions. 02638 TInfo m_Info; 02639 }; 02640 02641 02642 02643 /// Diagnostic message file. 02644 #define DIAG_MESSAGE_FILE "MessageFile" 02645 02646 /// Set handler for processing error codes. 02647 /// 02648 /// By default this handler is unset. 02649 /// NcbiApplication can init itself only if registry key DIAG_MESSAGE_FILE 02650 /// section DEBUG) is specified. The value of this key should be a name 02651 /// of the file with the error codes explanations. 02652 02653 extern void SetDiagErrCodeInfo(CDiagErrCodeInfo* info, 02654 bool can_delete = true); 02655 02656 /// Indicates whether an error-code processing handler has been set. 02657 02658 extern bool IsSetDiagErrCodeInfo(); 02659 02660 /// Get handler for processing error codes. 02661 02662 extern CDiagErrCodeInfo* GetDiagErrCodeInfo(bool take_ownership = false); 02663 02664 02665 /* @} */ 02666 02667 02668 /////////////////////////////////////////////////////// 02669 // All inline function implementations and internal data 02670 // types, etc. are in this file 02671 02672 #include <corelib/ncbidiag.inl> 02673 02674 02675 END_NCBI_SCOPE 02676 02677 02678 #endif /* CORELIB___NCBIDIAG__HPP */ 02679 02680
1.4.6
Modified on Mon Dec 07 16:20:35 2009 by modify_doxy.py rev. 173732