include/corelib/ncbidiag.hpp

Go to the documentation of this file.
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 

Generated on Sun Dec 6 21:58:48 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Mon Dec 07 16:20:35 2009 by modify_doxy.py rev. 173732