1 #ifndef CORELIB___NCBIDIAG__HPP
2 #define CORELIB___NCBIDIAG__HPP
3 
4 /*  $Id: ncbidiag.hpp 627019 2021-03-08 17:25:17Z ivanov $
5  * ===========================================================================
6  *
7  *                            PUBLIC DOMAIN NOTICE
8  *               National Center for Biotechnology Information
9  *
10  *  This software/database is a "United States Government Work" under the
11  *  terms of the United States Copyright Act.  It was written as part of
12  *  the author's official duties as a United States Government employee and
13  *  thus cannot be copyrighted.  This software/database is freely available
14  *  to the public for use. The National Library of Medicine and the U.S.
15  *  Government have not placed any restriction on its use or reproduction.
16  *
17  *  Although all reasonable efforts have been taken to ensure the accuracy
18  *  and reliability of the software and data, the NLM and the U.S.
19  *  Government do not and cannot warrant the performance or results that
20  *  may be obtained by using this software or data. The NLM and the U.S.
21  *  Government disclaim all warranties, express or implied, including
22  *  warranties of performance, merchantability or fitness for any particular
23  *  purpose.
24  *
25  *  Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Author:  Denis Vakatov
30  *
31  *
32  */
33 
34 /// @file ncbidiag.hpp
35 ///
36 ///   Defines NCBI C++ diagnostic APIs, classes, and macros.
37 ///
38 ///   More elaborate documentation could be found in:
39 ///     http://ncbi.github.io/cxx-toolkit/pages/ch_log.html
40 
41 
42 #include <corelib/ncbi_stack.hpp>
43 #include <deque>
44 #include <vector>
45 #include <map>
46 #include <atomic>
47 #include <stdexcept>
48 
49 
50 /** @addtogroup Diagnostics
51  *
52  * @{
53  */
54 
55 
56 BEGIN_NCBI_SCOPE
57 
58 /// Incapsulate compile time information such as
59 /// __FILE__, __LINE__, NCBI_MODULE, current function.
60 /// @note
61 ///   NCBI_MODULE is used only in .cpp files
62 /// @sa
63 ///   DIAG_COMPILE_INFO
64 class CDiagCompileInfo
65 {
66 public:
67     // DO NOT create CDiagCompileInfo directly
68     // use macro DIAG_COMPILE_INFO instead!
69     NCBI_XNCBI_EXPORT
70     CDiagCompileInfo(void);
71     NCBI_XNCBI_EXPORT
72     CDiagCompileInfo(const char* file,
73                      int         line,
74                      const char* curr_funct = NULL,
75                      const char* module = NULL);
76     NCBI_XNCBI_EXPORT
77     CDiagCompileInfo(const string& file,
78                      int           line,
79                      const string& curr_funct,
80                      const string& module);
81     NCBI_XNCBI_EXPORT
82     ~CDiagCompileInfo(void);
83 
84     const char*   GetFile    (void) const;
85     const char*   GetModule  (void) const;
86     int           GetLine    (void) const;
87     const string& GetClass   (void) const;
88     const string& GetFunction(void) const;
89 
90 private:
91     friend class CNcbiDiag;
92 
93     void SetFile(const string& file);
94     void SetModule(const string& module);
95 
96     NCBI_XNCBI_EXPORT
97     void SetLine(int line);
98     // Setting function also sets class if it has not been set explicitly.
99     void SetFunction(const string& func);
100     // Override any class name parsed from function name.
101     void SetClass(const string& cls);
102 
103     NCBI_XNCBI_EXPORT
104     void ParseCurrFunctName(void) const;
105 
106     // Check if module needs to be set
107     bool x_NeedModule(void) const;
108 
109     const char*    m_File;
110     const char*    m_Module;
111     int            m_Line;
112 
113     const   char*  m_CurrFunctName;
114     mutable bool   m_Parsed;
115     mutable bool   m_ClassSet;
116     mutable string m_ClassName;
117     mutable string m_FunctName;
118 
119     // Storage for data passed as strings rather than char*.
120     string         m_StrFile;
121     string         m_StrModule;
122     string         m_StrCurrFunctName;
123 };
124 
125 NCBI_XNCBI_EXPORT const char* g_DiagUnknownFunction(void);
126 
127 /// Get current function name.
128 /// Defined inside of either a method or a function body only.
129 // Based on boost's BOOST_CURRENT_FUNCTION
130 
131 #if defined(__GNUC__) || (defined(__MWERKS__) && (__MWERKS__ >= 0x3000)) || (defined(__ICC) && (__ICC >= 600))
132 #  define NCBI_CURRENT_FUNCTION __PRETTY_FUNCTION__
133 #elif defined(__FUNCSIG__)
134 #  define NCBI_CURRENT_FUNCTION __FUNCSIG__
135 #elif (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 600)) || (defined(__IBMCPP__) && (__IBMCPP__ >= 500))
136 #  define NCBI_CURRENT_FUNCTION __FUNCTION__
137 #elif defined(__BORLANDC__) && (__BORLANDC__ >= 0x550)
138 #  define NCBI_CURRENT_FUNCTION __FUNC__
139 #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
140 #  define NCBI_CURRENT_FUNCTION __func__
141 #else
142 #  define NCBI_CURRENT_FUNCTION NCBI_NS_NCBI::g_DiagUnknownFunction()
143 #endif
144 
145 
146 /// Set default module name based on NCBI_MODULE macro
147 ///
148 /// @sa DIAG_COMPILE_INFO
149 #define NCBI_MAKE_MODULE(module) NCBI_AS_STRING(module)
150 
151 /// Make compile time diagnostic information object
152 /// to use in CNcbiDiag and CException.
153 ///
154 /// This macro along with functionality of macro NCBI_MAKE_MODULE and
155 /// of constructor CDiagCompileInfo ensures that if variable NCBI_MODULE
156 /// will be defined then its value will be used as module name, but if it
157 /// isn't defined then module name in CDiagCompileInfo will be empty.
158 /// "Checking" of definition of NCBI_MODULE is performed at the moment
159 /// of macro issuing so you can define and redefine NCBI_MODULE several
160 /// times during one cpp-file. But BE WARNED that macro NCBI_MODULE is
161 /// considered as not defined when used in any header file. So if you want
162 /// for example make some error posting from inline function defined in
163 /// hpp-file and want your custom module name to be shown in error
164 /// message then you have to use MDiagModule manipulator as following:
165 ///
166 /// ERR_POST_X(1, MDiagModule("MY_MODULE_NAME") << "Error message" );
167 ///
168 /// @sa
169 ///   CDiagCompileInfo
170 #define DIAG_COMPILE_INFO                                           \
171     NCBI_NS_NCBI::CDiagCompileInfo(__FILE__,                        \
172                                    __LINE__,                        \
173                                    NCBI_CURRENT_FUNCTION,           \
174                                    NCBI_MAKE_MODULE(NCBI_MODULE))
175 
176 
177 
178 
179 /// Error posting with file, line number information but without error codes.
180 /// This macro is deprecated and it's strongly recomended to move
181 /// in all projects (except tests) to macro ERR_POST_X to make possible more
182 /// flexible error statistics and logging.
183 ///
184 /// @sa
185 ///   ERR_POST_EX, ERR_POST_X
186 #define ERR_POST(message)                                 \
187     ( NCBI_NS_NCBI::CNcbiDiag(DIAG_COMPILE_INFO).GetRef() \
188       << message                                          \
189       << NCBI_NS_NCBI::Endm )
190 
191 /// Wrappers for ERR_POST family of macros checking if the desired
192 /// severity is enabled.
193 ///
194 /// @sa
195 ///   ERR_POST, ERR_POST_X, ERR_POST_EX
196 #define SEVERITY_POST(severity, message)                  \
197     do if (NCBI_NS_NCBI::IsVisibleDiagPostLevel(NCBI_NS_NCBI::eDiag_##severity)) \
198             ERR_POST(severity << message); while(0)
199 #define WARNING_POST(message) SEVERITY_POST(Warning, message)
200 #define INFO_POST(message) SEVERITY_POST(Info, message)
201 #define TRACE_POST(message) SEVERITY_POST(Trace, message)
202 #define SEVERITY_POST_X(severity, subcode, message)       \
203     do if (NCBI_NS_NCBI::IsVisibleDiagPostLevel(NCBI_NS_NCBI::eDiag_##severity)) \
204             ERR_POST_X(subcode, severity << message); while(0)
205 #define WARNING_POST_X(subcode, message) SEVERITY_POST_X(Warning, subcode, message)
206 #define INFO_POST_X(subcode, message) SEVERITY_POST_X(Info, subcode, message)
207 #define TRACE_POST_X(subcode, message) SEVERITY_POST_X(Trace, subcode, message)
208 #define SEVERITY_POST_EX(severity, errcode, subcode, message) \
209     do if (NCBI_NS_NCBI::IsVisibleDiagPostLevel(NCBI_NS_NCBI::eDiag_##severity)) \
210             ERR_POST_EX(errcode, subcode, severity << message); while(0)
211 #define WARNING_POST_EX(errcode, subcode, message) SEVERITY_POST_EX(Warning, errcode, subcode, message)
212 #define INFO_POST_EX(errcode, message) SEVERITY_POST_EX(Info, errcode, subcode, message)
213 #define TRACE_POST_EX(errcode, message) SEVERITY_POST_EX(Trace, errcode, subcode, message)
214 
215 // When printing a message in 'old' (human readable) format LOG_POST skips
216 // all fields except the message.
217 /// This macro is deprecated and it's strongly recomended to move
218 /// in all projects (except tests) to macro LOG_POST_X to make possible more
219 /// flexible error statistics and logging.
220 ///
221 /// @sa
222 ///   LOG_POST_EX, LOG_POST_X
223 #define LOG_POST(message)                                               \
224     ( NCBI_NS_NCBI::CNcbiDiag(DIAG_COMPILE_INFO,                        \
225       NCBI_NS_NCBI::eDiag_Error,                                        \
226       NCBI_NS_NCBI::eDPF_Log | NCBI_NS_NCBI::eDPF_IsNote).GetRef()      \
227       << message                                                        \
228       << NCBI_NS_NCBI::Endm )
229 
230 /// Posting fatal error and abort.
231 /// This macro is deprecated and it's strongly recomended to move in all
232 /// projects (except tests) to macro ERR_FATAL_X to make possible more
233 /// flexible error statistics and logging.
234 ///
235 /// @sa
236 ///   ERR_FATAL_X, ERR_POST
237 #define ERR_FATAL(message)                                              \
238     NCBI_NS_NCBI::EndmFatal(NCBI_NS_NCBI::CNcbiDiag(DIAG_COMPILE_INFO,  \
239         NCBI_NS_NCBI::eDiag_Fatal).GetRef() << message )
240 
241 /// Error posting with error codes.
242 /// This macro should be used only when you need to make non-constant
243 /// error subcode. In all other cases it's strongly recomended to move
244 /// in all projects (except tests) to macro ERR_POST_X to make possible more
245 /// flexible error statistics and logging.
246 ///
247 /// @sa
248 ///   ERR_POST, ERR_POST_X
249 #define ERR_POST_EX(err_code, err_subcode, message)          \
250     ( NCBI_NS_NCBI::CNcbiDiag(DIAG_COMPILE_INFO).GetRef()    \
251       << NCBI_NS_NCBI::ErrCode( (err_code), (err_subcode) )  \
252       << message                                             \
253       << NCBI_NS_NCBI::Endm )
254 
255 #define LOG_POST_EX(err_code, err_subcode, message)          \
256     ( NCBI_NS_NCBI::CNcbiDiag(DIAG_COMPILE_INFO,                        \
257       NCBI_NS_NCBI::eDiag_Error,                                        \
258       NCBI_NS_NCBI::eDPF_Log | NCBI_NS_NCBI::eDPF_IsNote).GetRef()      \
259       << NCBI_NS_NCBI::ErrCode( (err_code), (err_subcode) )  \
260       << message                                             \
261       << NCBI_NS_NCBI::Endm )
262 
263 #define ERR_FATAL_EX(err_code, err_subcode, message)                    \
264     NCBI_NS_NCBI::EndmFatal(NCBI_NS_NCBI::CNcbiDiag(DIAG_COMPILE_INFO,  \
265         NCBI_NS_NCBI::eDiag_Fatal).GetRef() <<                          \
266         NCBI_NS_NCBI::ErrCode( (err_code), (err_subcode) ) << message )
267 
268 /// Define global error code name with given value (err_code) and given
269 /// maximum value of error subcode within this code. To use defined error
270 /// code you need to define symbol NCBI_USE_ERRCODE_X with name as its value.
271 /// This error code is used only in ERR_POST_X macro. Maximum
272 /// value of error subcode is being checked during compilation and
273 /// exists for developers to know what code they can use in next inserted
274 /// ERR_POST_X call (i.e. when one want to insert new ERR_POST_X call he has
275 /// to find definition of error code used in the source file, increase value
276 /// of maximum subcode and put result in ERR_POST_X call).
277 /// Definition of error code and its maximum subcode can be split into 2
278 /// independent macros to avoid recompilation of everything that includes
279 /// header with error code definition. For more information about it see
280 /// NCBI_DEFINE_ERR_SUBCODE_X.
281 /// Macro MUST be used inside ncbi scope.
282 ///
283 /// Example:
284 /// NCBI_DEFINE_ERRCODE_X(Corelib_Util, 110, 5);
285 /// ...
286 /// #define NCBI_USE_ERRCODE_X   Corelib_Util
287 /// ...
288 /// ERR_POST_X(3, "My error message with variables " << var);
289 ///
290 ///
291 /// @sa
292 ///   NCBI_DEFINE_ERR_SUBCODE_X, ERR_POST_X,
293 ///   NCBI_ERRCODE_X, NCBI_MAX_ERR_SUBCODE_X
294 #define NCBI_DEFINE_ERRCODE_X(name, err_code, max_err_subcode)  \
295     namespace err_code_x {                                      \
296         enum {                                                  \
297             eErrCodeX_##name     = err_code,                    \
298             eErrCodeX_Max_##name = max_err_subcode              \
299         };                                                      \
300         template <bool dummy>                                   \
301         struct SErrCodeX_Max_##name {                           \
302             enum {                                              \
303                 value = max_err_subcode,                        \
304                 dumm_dumm = int(dummy)                          \
305             };                                                  \
306         };                                                      \
307     }                                                           \
308     NCBI_EAT_SEMICOLON(err_code)
309 
310 /// Define maximum value of subcode for the error code currently in use.
311 /// Currently used error code is defined by macro NCBI_USE_ERRCODE_X. This
312 /// macro is a simplified version of NCBI_DEFINE_ERR_SUBCODE_XX and can be
313 /// handy to use when some error code is used only in one source file and no
314 /// other error code is used in the same source file.
315 /// To use this macro you must put 0 as max_err_subcode in
316 /// NCBI_DEFINE_ERRCODE_X macro. Otherwise compilation error will occur.
317 /// Macro MUST be used inside ncbi scope.
318 ///
319 /// Example:
320 /// NCBI_DEFINE_ERRCODE_X(Corelib_Util, 110, 0);
321 /// ...
322 /// #define NCBI_USE_ERRCODE_X   Corelib_Util
323 /// NCBI_DEFINE_ERR_SUBCODE_X(5);
324 /// ...
325 /// ERR_POST_X(3, "My error message with variables " << var);
326 ///
327 ///
328 /// @sa
329 ///   NCBI_DEFINE_ERRCODE_X, NCBI_DEFINE_ERR_SUBCODE_XX
330 #define NCBI_DEFINE_ERR_SUBCODE_X(max_err_subcode)              \
331     NCBI_DEFINE_ERR_SUBCODE_XX(NCBI_USE_ERRCODE_X, max_err_subcode)
332 
333 /// Define maximum value of subcode for particular error code name.
334 /// To use this macro you must put 0 as max_err_subcode in
335 /// NCBI_DEFINE_ERRCODE_X macro. Otherwise compilation error will occur.
336 /// Macro can be used only once per compilation unit.
337 /// Macro MUST be used inside ncbi scope.
338 ///
339 /// Example:
340 /// NCBI_DEFINE_ERRCODE_X(Corelib_Util, 110, 0);
341 /// ...
342 /// NCBI_DEFINE_ERR_SUBCODE_XX(Corelib_Util, 5);
343 /// ...
344 /// #define NCBI_USE_ERRCODE_X   Corelib_Util
345 /// ...
346 /// ERR_POST_X(3, "My error message with variables " << var);
347 ///
348 ///
349 /// @sa
350 ///   NCBI_DEFINE_ERRCODE_X
351 #define NCBI_DEFINE_ERR_SUBCODE_XX(name, max_err_subcode)       \
352     NCBI_CHECK_ERRCODE_USAGE(name)                              \
353     namespace err_code_x {                                      \
354         template <>                                             \
355         struct NCBI_NAME2(SErrCodeX_Max_, name)<true> {         \
356             enum {                                              \
357                 value = max_err_subcode                         \
358             };                                                  \
359         };                                                      \
360     }
361 
362 
363 /// Returns value of error code by its name defined by NCBI_DEFINE_ERRCODE_X
364 ///
365 /// @sa NCBI_DEFINE_ERRCODE_X
366 #define NCBI_ERRCODE_X_NAME(name)   \
367     NCBI_NS_NCBI::err_code_x::NCBI_NAME2(eErrCodeX_, name)
368 
369 /// Returns currently set default error code. Default error code is set by
370 /// definition of NCBI_USE_ERRCODE_X with name of error code as its value.
371 ///
372 /// @sa NCBI_DEFINE_ERRCODE_X
373 #define NCBI_ERRCODE_X   NCBI_ERRCODE_X_NAME(NCBI_USE_ERRCODE_X)
374 
375 /// Returns maximum value of error subcode within error code with given name.
376 ///
377 /// @sa NCBI_DEFINE_ERRCODE_X
378 #define NCBI_MAX_ERR_SUBCODE_X_NAME(name)   \
379     NCBI_NS_NCBI::err_code_x::NCBI_NAME2(SErrCodeX_Max_, name)<true>::value
380 
381 /// Returns maximum value of error subcode within current default error code.
382 ///
383 /// @sa NCBI_DEFINE_ERRCODE_X
384 #define NCBI_MAX_ERR_SUBCODE_X   \
385     NCBI_MAX_ERR_SUBCODE_X_NAME(NCBI_USE_ERRCODE_X)
386 
387 
388 /// Template structure used to point out wrong error subcode in
389 /// ERR_POST_X, STD_CATCH_X and alike macros. When error subcode that is
390 /// greater than maximum defined in NCBI_DEFINE_ERRCODE_X or
391 /// NCBI_DEFINE_ERR_SUBCODE_X will be used compiler will give an error and in
392 /// text of this error you'll see the name of this structure. In parameters of
393 /// template instantiation (that will be also shown in error message) you'll
394 /// see error code currently active, error subcode used in *_POST_X macro and
395 /// maximum error subcode valid for active error code.
396 ///
397 /// @sa
398 ///   NCBI_DEFINE_ERRCODE_X, NCBI_DEFINE_ERR_SUBCODE_X, ERR_POST_X
399 template <int errorCode, int errorSubcode, int maxErrorSubcode, bool isWrong>
400 struct WRONG_ERROR_SUBCODE_IN_POST_MACRO;
401 
402 /// Specialization of template: when error subcode is valid existence
403 /// of this specialization will be valuable for not issuing compiler error.
404 template <int errorCode, int errorSubcode, int maxErrorSubcode>
405 struct WRONG_ERROR_SUBCODE_IN_POST_MACRO
406             <errorCode, errorSubcode, maxErrorSubcode, false> {
407     enum {valid = 1};
408 };
409 
410 /// Template structure used to point out incorrect usage of
411 /// NCBI_DEFINE_ERR_SUBCODE_X macro i.e. when it's used for error code defined
412 /// with non-zero maximum subcode in NCBI_DEFINE_ERRCODE_X macro.
413 ///
414 /// @sa
415 ///   NCBI_DEFINE_ERRCODE_X, NCBI_DEFINE_ERR_SUBCODE_X
416 template <int errorCode, bool isWrong>
417 struct WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO;
418 
419 /// Specialization of template: when usage of NCBI_DEFINE_ERR_SUBCODE_X is
420 /// correct existence of this specialization will be valuable for not issuing
421 /// compiler error.
422 template <int errorCode>
423 struct WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO<errorCode, false> {
424     enum {valid = 1};
425 };
426 
427 /// Check that NCBI_DEFINE_ERR_SUBCODE_X is used for correctly defined error
428 /// code.
429 #define NCBI_CHECK_ERRCODE_USAGE(name)                              \
430     inline void NCBI_NAME2(s_ErrCodeCheck_, name) (                 \
431         NCBI_NS_NCBI::WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO <     \
432               NCBI_ERRCODE_X_NAME(name),                            \
433               NCBI_NS_NCBI::err_code_x::eErrCodeX_Max_##name != 0>  \
434                                                /*err_subcode*/)     \
435     {}
436 
437 
438 /// Additional dummy function for use in NCBI_CHECK_ERR_SUBCODE_X macro
CheckErrSubcodeX(int)439 inline void CheckErrSubcodeX(int)
440 {}
441 
442 /// Issue compile-time error if error subcode given is not valid for given
443 /// error code name.
444 /// This design is used for all compilers except early versions of gcc.
445 /// Though for MIPSpro and ICC it's not enough to make error message clear
446 /// (see addition below).
447 ///
448 /// @sa ERR_POST_X
449 #define NCBI_CHECK_ERR_SUBCODE_X_NAME(name, subcode)                  \
450     NCBI_NS_NCBI::CheckErrSubcodeX(                                   \
451         (int)sizeof(NCBI_NS_NCBI::WRONG_ERROR_SUBCODE_IN_POST_MACRO<  \
452               NCBI_ERRCODE_X_NAME(name), subcode,                     \
453               NCBI_MAX_ERR_SUBCODE_X_NAME(name),                      \
454               ((unsigned int)subcode >                                \
455                     (unsigned int)NCBI_MAX_ERR_SUBCODE_X_NAME(name))  \
456                                                                    >) \
457                                   )
458 
459 /// Issue compile-time error if error subcode given is not valid for current
460 /// error code.
461 #define NCBI_CHECK_ERR_SUBCODE_X(subcode)   \
462     NCBI_CHECK_ERR_SUBCODE_X_NAME(NCBI_USE_ERRCODE_X, subcode)
463 
464 /// Pass subcode as argument with check of its validity for given error code.
465 #define NCBI_ERR_SUBCODE_X_NAME(name, subcode)                  \
466     (NCBI_CHECK_ERR_SUBCODE_X_NAME(name, subcode), subcode)
467 
468 /// Pass subcode as argument with check of its validity for current error code.
469 #define NCBI_ERR_SUBCODE_X(subcode)                     \
470     (NCBI_CHECK_ERR_SUBCODE_X(subcode), subcode)
471 
472 #if defined(NCBI_COMPILER_ICC) || defined(NCBI_COMPILER_MIPSPRO)
473 
474 /// Additional not implemented template structure for use in
475 /// WRONG_ERROR_SUBCODE_IN_POST_MACRO structure specialization
476 template <int x>
477 struct WRONG_ERROR_SUBCODE_IN_POST_MACRO_2;
478 
479 /// Specialization of template structure used for ICC and MIPSpro
480 /// If this specialization doesn't exist these compilers doesn't show name
481 /// of unimplemented structure in error message. But when this specialization
482 /// exists and uses recursively another not implemented template structure
483 /// then WRONG_ERROR_SUBCODE_IN_POST_MACRO appears in error message and it
484 /// becomes clearer.
485 template <int errorCode, int errorSubcode, int maxErrorSubcode>
486 struct WRONG_ERROR_SUBCODE_IN_POST_MACRO
487             <errorCode, errorSubcode, maxErrorSubcode, true> {
488     typedef char t[sizeof(WRONG_ERROR_SUBCODE_IN_POST_MACRO_2<errorCode>)];
489 };
490 
491 /// Additional not implemented template structure for use in
492 /// WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO structure specialization
493 template <int x>
494 struct WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO_2;
495 
496 /// Specialization of template structure used for ICC and MIPSpro
497 /// If this specialization doesn't exist these compilers doesn't show name
498 /// of unimplemented structure in error message. But when this specialization
499 /// exists and uses recursively another not implemented template structure
500 /// then WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO appears in error message and
501 /// it becomes clearer.
502 template <int errorCode>
503 struct WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO<errorCode, true> {
504     typedef char t[sizeof(
505                        WRONG_USAGE_OF_DEFINE_ERR_SUBCODE_MACRO_2<errorCode>)];
506 };
507 
508 #endif  // if defined(NCBI_COMPILER_ICC) || defined(NCBI_COMPILER_MIPSPRO)
509 
510 
511 /// Error posting with default error code and given error subcode. Also
512 /// checks subcode correctness. When error subcode is incorrect (greater than
513 /// defined in NCBI_DEFINE_ERRCODE_X) compile-time error is issued.
514 /// All calls to ERR_POST_X under the same default error code
515 /// MUST be with deferent error subcodes to make possible more
516 /// flexible error statistics and logging.
517 /// If using the macro leads to compile errors containing strings
518 /// like "err_code_x" or "ErrCodeX" in messages, it means you didn't define
519 /// error code name with NCBI_DEFINE_ERRCODE_X macro or didn't select current
520 /// default error code with valid NCBI_USE_ERRCODE_X definition.
521 /// This macro allows the use of only constant error subcodes
522 /// (integer literals or enum constants). If you need to make variable error
523 /// subcode you need to use macro ERR_POST_EX as follows:
524 ///
525 /// NCBI_DEFINE_ERRCODE_X(Corelib_Util, 110, 5);
526 /// ...
527 /// #define NCBI_USE_ERRCODE_X   Corelib_Util
528 /// ...
529 /// ERR_POST_EX(NCBI_ERRCODE_X, my_subcode,
530 ///             "My error message with variables " << var);
531 ///
532 /// Or in more complicated way:
533 ///
534 /// NCBI_DEFINE_ERRCODE_X(Corelib_Util, 110, 5);
535 /// ...
536 /// // no need to define NCBI_USE_ERRCODE_X
537 /// ...
538 /// ERR_POST_EX(NCBI_ERRCODE_X_NAME(Corelib_Util), my_subcode,
539 ///             "My error message with variables " << var);
540 ///
541 /// It's strongly recommended to use macro NCBI_CHECK_ERR_SUBCODE_X
542 /// (or NCBI_CHECK_ERR_SUBCODE_X_NAME in complicated case) to check validity
543 /// of error subcodes in places where variable 'my_subcode' is assigned.
544 ///
545 ///
546 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, ERR_POST_EX
547 #define ERR_POST_X(err_subcode, message)                  \
548     ERR_POST_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
549 
550 #define LOG_POST_X(err_subcode, message)                  \
551     LOG_POST_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
552 
553 #define ERR_FATAL_X(err_subcode, message)                 \
554     ERR_FATAL_XX(NCBI_USE_ERRCODE_X, err_subcode, message)
555 
556 /// Error posting with error code having given name and with given error
557 /// subcode. Macro must be placed in headers instead of ERR_POST_X to not
558 /// confuse default error codes used in sources where this header is included.
559 ///
560 /// @sa NCBI_DEFINE_ERRCODE_X, ERR_POST_X
561 #define ERR_POST_XX(error_name, err_subcode, message)                   \
562     ERR_POST_EX(NCBI_ERRCODE_X_NAME(error_name),                        \
563                 NCBI_ERR_SUBCODE_X_NAME(error_name, err_subcode),       \
564                 message)
565 
566 #define LOG_POST_XX(error_name, err_subcode, message)   \
567     LOG_POST_EX(NCBI_ERRCODE_X_NAME(error_name),                        \
568                 NCBI_ERR_SUBCODE_X_NAME(error_name, err_subcode),       \
569                 message)
570 
571 #define ERR_FATAL_XX(error_name, err_subcode, message)                  \
572     ERR_FATAL_EX(NCBI_ERRCODE_X_NAME(error_name),                       \
573                  NCBI_ERR_SUBCODE_X_NAME(error_name, err_subcode),      \
574                  message)
575 
576 /// Common code for making log or error posting only given number of times
577 /// during program execution. This macro MUST not be used outside
578 /// this header.
579 #define NCBI_REPEAT_POST_N_TIMES(post_macro, count, params)     \
580     do {                                                        \
581         static atomic<int> sx_to_show(count);                   \
582         int to_show = sx_to_show;                               \
583         if ( to_show > 0 ) {                                    \
584             sx_to_show = to_show - 1;                           \
585             post_macro params;  /* parenthesis are in params */ \
586         }                                                       \
587     } while ( false )
588 
589 
590 /// Error posting only given number of times during program execution.
591 #define ERR_POST_N_TIMES(count, message)   \
592     NCBI_REPEAT_POST_N_TIMES( ERR_POST, count, (message) )
593 
594 #define LOG_POST_N_TIMES(count, message)   \
595     NCBI_REPEAT_POST_N_TIMES( LOG_POST, count, (message) )
596 
597 
598 /// Error posting only once during program execution.
599 #define ERR_POST_ONCE(message) ERR_POST_N_TIMES(1, message)
600 
601 #define LOG_POST_ONCE(message) LOG_POST_N_TIMES(1, message)
602 
603 
604 /// Error posting only given number of times during program execution
605 /// with default error code and given error subcode.
606 ///
607 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, ERR_POST_X
608 #define ERR_POST_X_N_TIMES(count, err_subcode, message)   \
609     NCBI_REPEAT_POST_N_TIMES( ERR_POST_X, count, (err_subcode, message) )
610 
611 #define LOG_POST_X_N_TIMES(count, err_subcode, message)   \
612     NCBI_REPEAT_POST_N_TIMES( LOG_POST_X, count, (err_subcode, message) )
613 
614 /// Error posting only once during program execution with default
615 /// error code and given error subcode.
616 ///
617 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, ERR_POST_X
618 #define ERR_POST_X_ONCE(err_subcode, message)   \
619     ERR_POST_X_N_TIMES(1, err_subcode, message)
620 
621 #define LOG_POST_X_ONCE(err_subcode, message)   \
622     LOG_POST_X_N_TIMES(1, err_subcode, message)
623 
624 /// Error posting only given number of times during program execution
625 /// with given error code name and given error subcode.
626 ///
627 /// @sa NCBI_DEFINE_ERRCODE_X, ERR_POST_XX
628 #define ERR_POST_XX_N_TIMES(count, error_name, err_subcode, message)   \
629     NCBI_REPEAT_POST_N_TIMES( ERR_POST_XX, count,                      \
630                               (error_name, err_subcode, message) )
631 
632 #define LOG_POST_XX_N_TIMES(count, error_name, err_subcode, message)   \
633     NCBI_REPEAT_POST_N_TIMES( LOG_POST_XX, count,                      \
634                               (error_name, err_subcode, message) )
635 
636 /// Error posting only once during program execution with given
637 /// error code name and given error subcode.
638 ///
639 /// @sa NCBI_DEFINE_ERRCODE_X, NCBI_ERRCODE_X, ERR_POST_XX
640 #define ERR_POST_XX_ONCE(error_name, err_subcode, message)   \
641     ERR_POST_XX_N_TIMES(1, error_name, err_subcode, message)
642 
643 #define LOG_POST_XX_ONCE(error_name, err_subcode, message)   \
644     LOG_POST_XX_N_TIMES(1, error_name, err_subcode, message)
645 
646 /// Severity level for the posted diagnostics.
647 enum EDiagSev {
648     eDiag_Info = 0, ///< Informational message
649     eDiag_Warning,  ///< Warning message
650     eDiag_Error,    ///< Error message
651     eDiag_Critical, ///< Critical error message
652     eDiag_Fatal,    ///< Fatal error -- guarantees exit(or abort)
653     //
654     eDiag_Trace,    ///< Trace message
655 
656     // Limits
657     eDiagSevMin = eDiag_Info,  ///< Verbosity level for min. severity
658     eDiagSevMax = eDiag_Trace  ///< Verbosity level for max. severity
659 };
660 
661 
662 /// Severity level change state.
663 enum EDiagSevChange {
664     eDiagSC_Unknown, ///< Status of changing severity is unknown (first call)
665     eDiagSC_Disable, ///< Disable change severity level
666     eDiagSC_Enable   ///< Enable change severity level
667 };
668 
669 
670 /// Which parts of the diagnostic context should be posted.
671 ///
672 /// Generic appearance of the posted message is as follows:
673 ///
674 ///   [<date> <time> ][T<TID> ][["[<path>]/<file>", ][line <line>]: ]
675 ///   [<severity>: ][(<err_code>.<err_subcode>) ]
676 ///   [<module>[::<class>]::][<function>()] - [<prefix1>::<prefix2>::<prefixN>] <message>\n[
677 ///   [<err_code_message>\n]
678 ///   [<err_code_explanation>\n]
679 ///
680 /// Example:
681 ///
682 /// - If all flags are set, and prefix string is set to "My prefix", and
683 ///   ERR_POST(eDiag_Warning, "Take care!"):
684 ///   "/home/iam/myfile.cpp", line 33: Warning: (2.11)
685 ///   Module::Class::Function() - [My prefix] Take care!
686 ///
687 /// @sa
688 ///   SDiagMessage::Compose()
689 enum EDiagPostFlag {
690     eDPF_File = 1 << 0,                 ///< File name (not full path)
691     eDPF_LongFilename = 1 << 1,         ///< Full file path
692     eDPF_Line = 1 << 2,                 ///< Source line
693     eDPF_Prefix = 1 << 3,               ///< Prefix (default)
694     eDPF_Severity = 1 << 4,             ///< Severity (default)
695     eDPF_ErrorID = 1 << 5,              ///< Error code and subcode (default)
696 
697     eDPF_DateTime = 1 << 7,             ///< Include date and time
698     eDPF_ErrCodeMessage = 1 << 8,       ///< Error code message (default)
699     eDPF_ErrCodeExplanation = 1 << 9,   ///< Error explanation (default)
700     eDPF_ErrCodeUseSeverity = 1 << 10,  ///< Use severity from error code (default)
701     eDPF_Location = 1 << 11,            ///< Include class and function if any
702     eDPF_TID = 1 << 13,                 ///< Thread ID
703 
704     eDPF_PID = 0,                       ///< @deprecated
705     eDPF_SerialNo = 0,                  ///< @deprecated
706     eDPF_SerialNo_Thread = 0,           ///< @deprecated
707     eDPF_RequestId = 0,                 ///< @deprecated
708     eDPF_Iteration = eDPF_RequestId,    ///< @deprecated
709     eDPF_UID = 0,                       ///< @deprecated
710 
711     eDPF_ErrCode = eDPF_ErrorID,        ///< @deprecated
712     eDPF_ErrSubCode = eDPF_ErrorID,     ///< @deprecated
713 
714     /// All flags (except for the "unusual" ones!)
715     eDPF_All = 0x7FFFF,
716 
717     /// Default flags to use when tracing.
718 #if defined(NCBI_THREADS)
719     eDPF_Trace              = eDPF_File |
720                               eDPF_LongFilename |
721                               eDPF_Line |
722                               eDPF_Prefix |
723                               eDPF_Severity |
724                               eDPF_Location |
725                               eDPF_PID |
726                               eDPF_TID |
727                               eDPF_SerialNo |
728                               eDPF_SerialNo_Thread,
729 #else
730     eDPF_Trace              = eDPF_File |
731                               eDPF_LongFilename |
732                               eDPF_Line |
733                               eDPF_Prefix |
734                               eDPF_Severity |
735                               eDPF_Location |
736                               eDPF_PID |
737                               eDPF_SerialNo,
738 #endif
739 
740     /// Default flags to use for exception formatting.
741     eDPF_Exception = eDPF_Trace | eDPF_ErrorID,
742 
743     /// Print the posted message only; without severity, location, prefix, etc.
744     eDPF_Log                = 0,
745 
746     // "Unusual" flags -- not included in "eDPF_All"
747     eDPF_ErrCodeMsgInFront  = 1 << 19, ///< Put ErrCode text in front of the message
748     eDPF_MergeLines         = 1 << 21, ///< Escape EOLs.
749     eDPF_PreMergeLines      = eDPF_MergeLines, ///< Obsolete. Use eDPF_MergeLines.
750     eDPF_OmitInfoSev        = 1 << 22, ///< No sev. indication if eDiag_Info
751     eDPF_OmitSeparator      = 1 << 23, ///< No '---' separator before message
752 
753     eDPF_AppLog             = 1 << 24, ///< Post message to application log
754     eDPF_IsNote             = 1 << 25, ///< Print "Note[X]" severity name.
755     eDPF_IsMessage          = eDPF_IsNote, // Legacy name
756 
757     /// This flag is deprecated and ignored - all log writes are atomic.
758     /// For compatibility IsSetDiagPostFlag always returns true when
759     /// asked about this flag.
760     eDPF_AtomicWrite        = 1 << 26, ///< @deprecated
761 
762     /// Send the message to 'console' regardless of it's severity.
763     /// To be set by 'Console' manipulator only.
764     eDPF_IsConsole          = 1 << 27,
765 
766     /// Use global default flags (merge with).
767     /// @sa SetDiagPostFlag(), UnsetDiagPostFlag(), IsSetDiagPostFlag()
768     eDPF_Default            = 1 << 28,
769 
770     /// Important bits which should be taken from the globally set flags
771     /// even if a user attempts to override (or forgets to set) them
772     /// when calling CNcbiDiag().
773     eDPF_ImportantFlagsMask = eDPF_MergeLines |
774                               eDPF_OmitInfoSev |
775                               eDPF_OmitSeparator,
776 
777     /// Use flags provided by user as-is, do not allow CNcbiDiag to replace
778     /// "important" flags by the globally set ones.
779     eDPF_UseExactUserFlags  = 1 << 29
780 };
781 
782 typedef int TDiagPostFlags;  ///< Binary OR of "EDiagPostFlag"
783 
784 
785 /// Application execution states shown in the std prefix
786 enum EDiagAppState {
787     eDiagAppState_NotSet,        ///< Reserved value, never used in messages
788     eDiagAppState_AppBegin,      ///< AB
789     eDiagAppState_AppRun,        ///< A
790     eDiagAppState_AppEnd,        ///< AE
791     eDiagAppState_RequestBegin,  ///< RB
792     eDiagAppState_Request,       ///< R
793     eDiagAppState_RequestEnd     ///< RE
794 };
795 
796 
797 // Forward declaration of some classes.
798 class CDiagBuffer;
799 class CDiagErrCodeInfo;
800 
801 
802 
803 /////////////////////////////////////////////////////////////////////////////
804 ///
805 /// ErrCode --
806 ///
807 /// Define composition of error code.
808 ///
809 /// Currently the error code is an ordered pair of <code, subcode> numbers.
810 
811 class ErrCode
812 {
813 public:
814     /// Constructor.
ErrCode(int code,int subcode=0)815     ErrCode(int code, int subcode = 0)
816         : m_Code(code), m_SubCode(subcode)
817     { }
818     int m_Code;         ///< Major error code number
819     int m_SubCode;      ///< Minor error code number
820 };
821 
822 
823 /////////////////////////////////////////////////////////////////////////////
824 ///
825 /// Severity --
826 ///
827 /// Set post severity to a given level.
828 
829 class Severity
830 {
831 public:
Severity(EDiagSev sev)832     Severity(EDiagSev sev)
833         : m_Level(sev) {}
834     EDiagSev m_Level;         ///< Severity level
835 };
836 
837 
838 /////////////////////////////////////////////////////////////////////////////
839 ///
840 /// SetPostFlags --
841 ///
842 /// Set specific post flags.
843 
844 class SetPostFlags
845 {
846 public:
SetPostFlags(TDiagPostFlags flags)847     SetPostFlags(TDiagPostFlags flags)
848         : m_Flags(flags) {}
849     TDiagPostFlags m_Flags;         ///< flags to set
850 };
851 
852 
853 class CNcbiDiag;
854 
855 /////////////////////////////////////////////////////////////////////////////
856 ///
857 /// MDiagModule --
858 ///
859 /// Manipulator to set Module for CNcbiDiag
860 
861 class MDiagModule
862 {
863 public:
864     MDiagModule(const char* module);
865     friend const CNcbiDiag& operator<< (const CNcbiDiag&   diag,
866                                         const MDiagModule& module);
867 private:
868     const char* m_Module;
869 };
870 
871 
872 
873 /////////////////////////////////////////////////////////////////////////////
874 ///
875 /// MDiagClass --
876 ///
877 /// Manipulator to set Class for CNcbiDiag
878 
879 class MDiagClass
880 {
881 public:
882     MDiagClass(const char* nclass);
883     friend const CNcbiDiag& operator<< (const CNcbiDiag&  diag,
884                                         const MDiagClass& nclass);
885 private:
886     const char* m_Class;
887 };
888 
889 
890 
891 /////////////////////////////////////////////////////////////////////////////
892 ///
893 /// MDiagFunction --
894 ///
895 /// Manipulator to set Function for CNcbiDiag
896 
897 class MDiagFunction
898 {
899 public:
900     MDiagFunction(const char* function);
901     friend const CNcbiDiag& operator<< (const CNcbiDiag&     diag,
902                                         const MDiagFunction& function);
903 private:
904     const char* m_Function;
905 };
906 
907 
908 //
909 class CException;
910 class CStackTrace;
911 
912 
913 /////////////////////////////////////////////////////////////////////////////
914 ///
915 /// CNcbiDiag --
916 ///
917 /// Define the main NCBI Diagnostic class.
918 
919 
920 class CNcbiDiag
921 {
922 public:
923     /// Constructor.
924     NCBI_XNCBI_EXPORT  CNcbiDiag
925     (EDiagSev       sev        = eDiag_Error,  ///< Severity level
926      TDiagPostFlags post_flags = eDPF_Default  ///< What to post
927      );
928 
929 
930     /// Constructor -- includes the file and line number info
931     NCBI_XNCBI_EXPORT  CNcbiDiag
932     (const CDiagCompileInfo& info,                      ///< File, line, module
933      EDiagSev                sev        = eDiag_Error,  ///< Severity level
934      TDiagPostFlags          post_flags = eDPF_Default  ///< What to post
935      );
936 
937     /// Destructor.
938     NCBI_XNCBI_EXPORT ~CNcbiDiag(void);
939 
940     /// Some compilers (e.g. GCC 3.4.0) fail to use temporary objects as
941     /// function arguments if there's no public copy constructor.
942     /// Rather than using the temporary, get a reference from this method.
GetRef(void) const943     const CNcbiDiag& GetRef(void) const { return *this; }
944 
945     /// Generic method to post to diagnostic stream.
946     template<class X> const CNcbiDiag& Put(const volatile void*, const X& x) const;
947 
948     /// Diagnostic stream manipulator
949     /// @sa Reset(), Endm()
950     /// @sa Info(), Warning(), Error(), Critical(), Fatal(), Trace()
951     typedef const CNcbiDiag& (*FManip)(const CNcbiDiag&);
952     typedef IOS_BASE& (*FIosbaseManip)(IOS_BASE&);
953     typedef CNcbiIos& (*FIosManip)(CNcbiIos&);
954 
955     /// Helper method to post error code and subcode to diagnostic stream.
956     ///
957     /// Example:
958     ///   CNcbiDiag() << ErrCode(5,3) << "My message";
959     const CNcbiDiag& Put(const ErrCode*, const ErrCode& err_code) const;
960 
961     /// Helper method to set severity level.
962     ///
963     /// Example:
964     ///   CNcbiDiag() << Severity(eDiag_Error) << "My message";
965     const CNcbiDiag& Put(const Severity*, const Severity& severity) const;
966 
967     /// Helper method to post an exception to diagnostic stream.
968     ///
969     /// Example:
970     ///   CNcbiDiag() << ex;
971     template<class X> inline
Put(const CException *,const X & x) const972     const CNcbiDiag& Put(const CException*, const X& x) const {
973         return x_Put(x);
974     }
975 
976     template<class X> inline
Put(const exception *,const X & x) const977     const CNcbiDiag& Put(const exception*, const X& x) const {
978         const CException* xp = dynamic_cast<const CException*>(&x);
979         if ( xp ) {
980             return x_Put(*xp);
981         }
982         else {
983             string s = x.what();
984             return Put(&s, s);
985         }
986     }
987 
988     /// Helper method to post stack trace to diagnostic stream using
989     /// standard stack trace formatting.
990     ///
991     /// Example:
992     ///   CNcbiDiag() << "My message" << CStackTrace();
993     NCBI_XNCBI_EXPORT
994         const CNcbiDiag& Put(const CStackTrace*,
995                              const CStackTrace& stacktrace) const;
996 
997     /// Helper method to set specific post flags.
998     ///
999     /// Example:
1000     ///   CNcbiDiag() << SetPostFlags(eDPF_DateTime) << "My message";
1001     const CNcbiDiag& Put(const NCBI_NS_NCBI::SetPostFlags*,
1002                          const NCBI_NS_NCBI::SetPostFlags& flags) const;
1003 
1004     /// Helper method to handle various diagnostic stream manipulators.
1005     ///
1006     /// For example, to set the message severity level to INFO:
1007     ///   CNcbiDiag() << Info << "My message";
Put(const FManip,const FManip & manip) const1008     const CNcbiDiag& Put(const FManip, const FManip& manip) const
1009     {
1010         return manip(*this);
1011     }
operator <<(FManip manip) const1012     inline const CNcbiDiag& operator<< (FManip manip) const
1013     {
1014         return manip(*this);
1015     }
1016     const CNcbiDiag& operator<< (FIosbaseManip manip) const;
1017     const CNcbiDiag& operator<< (FIosManip manip) const;
1018 
1019     /// Post the arguments
1020     /// @sa Put()
operator <<(const X & x) const1021     template<class X> inline const CNcbiDiag& operator<< (const X& x) const
1022     {
1023         return Put(&x, x);
1024     }
1025 
1026     // Output manipulators for CNcbiDiag.
1027 
1028     /// Reset the content of current message.
1029     friend const CNcbiDiag& Reset   (const CNcbiDiag& diag);
1030 
1031     /// Flush current message, start new one.
1032     friend const CNcbiDiag& Endm    (const CNcbiDiag& diag);
1033 
1034     /// Flush current message, then set a severity for the next diagnostic
1035     /// message to INFO
1036     friend const CNcbiDiag& Info    (const CNcbiDiag& diag);
1037 
1038     /// Flush current message, then set a severity for the next diagnostic
1039     /// message to WARNING
1040     friend const CNcbiDiag& Warning (const CNcbiDiag& diag);
1041 
1042     /// Flush current message, then set a severity for the next diagnostic
1043     /// message to ERROR
1044     friend const CNcbiDiag& Error   (const CNcbiDiag& diag);
1045 
1046     /// Flush current message, then set a severity for the next diagnostic
1047     /// message to CRITICAL ERROR
1048     friend const CNcbiDiag& Critical(const CNcbiDiag& diag);
1049 
1050     /// Flush current message, then set a severity for the next diagnostic
1051     /// message to FATAL
1052     friend const CNcbiDiag& Fatal   (const CNcbiDiag& diag);
1053 
1054     /// Flush current message, then set a severity for the next diagnostic
1055     /// message to TRACE
1056     friend const CNcbiDiag& Trace   (const CNcbiDiag& diag);
1057 
1058     /// Set IsMessage flag to indicate that the current post is a message.
1059     /// Do not flush current post or change the severity. The flag is reset
1060     /// by the next Flush().
1061     /// @deprecated Use Note manipulator.
1062     friend const CNcbiDiag& Message (const CNcbiDiag& diag);
1063 
1064     /// Set IsNote flag to indicate that the current post is a note.
1065     /// Do not flush current post or change the severity. The flag is reset
1066     /// by the next Flush().
1067     friend const CNcbiDiag& Note    (const CNcbiDiag& diag);
1068 
1069     /// Set IsConsole flag to indicate that the current post should
1070     /// go to console regardless of its severity (in addition to the
1071     /// default output -- file etc.).
1072     /// Do not flush current post or change the severity. The flag is reset
1073     /// by the next Flush().
1074     friend const CNcbiDiag& Console (const CNcbiDiag& diag);
1075 
1076     /// Print stack trace
1077     friend const CNcbiDiag& StackTrace (const CNcbiDiag& diag);
1078 
1079     /// Get a common symbolic name for the severity levels.
1080     static const char* SeverityName(EDiagSev sev);
1081 
1082     /// Get severity from string.
1083     ///
1084     /// @param str_sev
1085     ///   Can be the numeric value or a symbolic name (see
1086     ///   CDiagBuffer::sm_SeverityName[]).
1087     /// @param sev
1088     ///   Severity level.
1089     /// @return
1090     ///   Return TRUE if severity level known; FALSE, otherwise.
1091     NCBI_XNCBI_EXPORT
1092     static bool StrToSeverityLevel(const char* str_sev, EDiagSev& sev);
1093 
1094     /// Set file name to post.
1095     NCBI_XNCBI_EXPORT
1096     const CNcbiDiag& SetFile(const char* file) const;
1097 
1098     /// Set module name.
1099     NCBI_XNCBI_EXPORT
1100     const CNcbiDiag& SetModule(const char* module) const;
1101 
1102     /// Set class name.
1103     NCBI_XNCBI_EXPORT
1104     const CNcbiDiag& SetClass(const char* nclass) const;
1105 
1106     /// Set function name.
1107     NCBI_XNCBI_EXPORT
1108     const CNcbiDiag& SetFunction(const char* function) const;
1109 
1110     /// Set line number for post.
1111     const CNcbiDiag& SetLine(size_t line) const;
1112 
1113     /// Set error code and subcode numbers.
1114     const CNcbiDiag& SetErrorCode(int code = 0, int subcode = 0) const;
1115 
1116     /// Get severity of the current message.
1117     EDiagSev GetSeverity(void) const;
1118 
1119     /// Get file used for the current message.
1120     const char* GetFile(void) const;
1121 
1122     /// Get line number for the current message.
1123     size_t GetLine(void) const;
1124 
1125     /// Get error code of the current message.
1126     int GetErrorCode(void) const;
1127 
1128     /// Get error subcode of the current message.
1129     int GetErrorSubCode(void) const;
1130 
1131     /// Get module name of the current message.
1132     const char* GetModule(void) const;
1133 
1134     /// Get class name of the current message.
1135     const char* GetClass(void) const;
1136 
1137     /// Get function name of the current message.
1138     const char* GetFunction(void) const;
1139 
1140     /// Check if filters are passed for the current message.
1141     /// In addition check an exception and all its backlog if specified.
1142     NCBI_XNCBI_EXPORT
1143     bool CheckFilters(const CException* ex = NULL) const;
1144 
1145     /// Get post flags for the current message.
1146     /// If the post flags have "eDPF_Default" set, then in the returned flags
1147     /// it will be reset and substituted by current default flags.
1148     TDiagPostFlags GetPostFlags(void) const;
1149 
1150     /// Set new post flags for the current message.
1151     void SetAllPostFlags(TDiagPostFlags flags) const;
1152 
1153     /// Set specific post flags for the current message.
1154     TDiagPostFlags SetPostFlags(TDiagPostFlags flags) const;
1155 
1156     /// Clear specific post flags for the current message.
1157     TDiagPostFlags ResetPostFlags(TDiagPostFlags flags) const;
1158 
1159     /// Display fatal error message.
1160     NCBI_NORETURN NCBI_XNCBI_EXPORT
1161     static void DiagFatal(const CDiagCompileInfo& info,
1162                           const char* message);
1163     /// Display trouble error message.
1164     NCBI_XNCBI_EXPORT
1165     static void DiagTrouble(const CDiagCompileInfo& info,
1166                             const char* message = NULL);
1167 
1168     /// Assert specified expression and report results.
1169     NCBI_NORETURN NCBI_XNCBI_EXPORT
1170     static void DiagAssert(const CDiagCompileInfo& info,
1171                            const char* expression,
1172                            const char* message = NULL);
1173 
1174     /// Same as DiagAssert but only if the system message box is suppressed.
1175     NCBI_XNCBI_EXPORT
1176     static void DiagAssertIfSuppressedSystemMessageBox(
1177         const CDiagCompileInfo& info,
1178         const char* expression,
1179         const char* message = NULL);
1180 
1181     /// Display validation message.
1182     NCBI_XNCBI_EXPORT
1183     static void DiagValidate(const CDiagCompileInfo& info,
1184                              const char* expression,
1185                              const char* message);
1186 
1187     /// @deprecated Use ResetIsNoteFlag()
ResetIsMessageFlag(void) const1188     void ResetIsMessageFlag(void) const { ResetIsNoteFlag(); }
1189 
1190     /// Reset IsNote flag.
ResetIsNoteFlag(void) const1191     void ResetIsNoteFlag(void) const { m_PostFlags &= ~eDPF_IsNote; }
1192 
1193     /// Reset IsConsole flag.
ResetIsConsoleFlag(void) const1194     void ResetIsConsoleFlag(void) const { m_PostFlags &= ~eDPF_IsConsole; }
1195 
GetOmitStackTrace(void) const1196     bool GetOmitStackTrace(void) const { return m_OmitStackTrace; }
SetOmitStackTrace(bool value)1197     void SetOmitStackTrace(bool value) { m_OmitStackTrace = value; }
1198 
1199     /// Set important flags to their globally set values
1200     /// @sa EDiagPostFlags
1201     static TDiagPostFlags ForceImportantFlags(TDiagPostFlags flags);
1202 
1203 private:
1204     mutable EDiagSev       m_Severity;     ///< Severity level of current msg
1205     mutable int            m_ErrCode;      ///< Error code
1206     mutable int            m_ErrSubCode;   ///< Error subcode
1207     CDiagBuffer&           m_Buffer;       ///< This thread's error msg. buffer
1208     mutable TDiagPostFlags m_PostFlags;    ///< Bitwise OR of "EDiagPostFlag"
1209     mutable bool           m_OmitStackTrace;
1210 
1211     mutable CDiagCompileInfo m_CompileInfo;
1212 
1213     /// Private replacement for Endm called from manipulators. Unlike Endm,
1214     /// does not reset ErrCode if buffer is not set.
1215     void x_EndMess(void) const;
1216 
1217     /// Helper func for the exception-related Put()
1218     /// @sa Put()
1219     NCBI_XNCBI_EXPORT const CNcbiDiag& x_Put(const CException& ex) const;
1220 
1221     /// Private copy constructor to prohibit copy.
1222     CNcbiDiag(const CNcbiDiag&);
1223 
1224     /// Private assignment operator to prohibit assignment.
1225     CNcbiDiag& operator= (const CNcbiDiag&);
1226 };
1227 
1228 
1229 
1230 /////////////////////////////////////////////////////////////////////////////
1231 // ATTENTION:  the following functions are application-wide, i.e they
1232 //             are not local for a particular thread
1233 /////////////////////////////////////////////////////////////////////////////
1234 
1235 
1236 /// Check if a specified flag is set.
1237 ///
1238 /// @param flag
1239 ///   Flag to check
1240 /// @param flags
1241 ///   If eDPF_Default is set for "flags" then use the current global flags on
1242 ///   its place (merged with other flags from "flags").
1243 /// @return
1244 ///   "TRUE" if the specified "flag" is set in global "flags" that describes
1245 ///   the post settings.
1246 /// @sa SetDiagPostFlag(), UnsetDiagPostFlag()
1247 inline bool IsSetDiagPostFlag(EDiagPostFlag  flag,
1248                               TDiagPostFlags flags = eDPF_Default);
1249 
1250 /// Set global post flags to "flags".
1251 /// If "flags" have flag eDPF_Default set, it will be replaced by the
1252 /// current global post flags.
1253 /// @return
1254 ///   Previously set flags
1255 NCBI_XNCBI_EXPORT
1256 extern TDiagPostFlags SetDiagPostAllFlags(TDiagPostFlags flags);
1257 
1258 /// Set the specified flag (globally).
1259 NCBI_XNCBI_EXPORT
1260 extern void SetDiagPostFlag(EDiagPostFlag flag);
1261 
1262 /// Unset the specified flag (globally).
1263 NCBI_XNCBI_EXPORT
1264 extern void UnsetDiagPostFlag(EDiagPostFlag flag);
1265 
1266 /// Versions of the above for extra trace flags.
1267 /// ATTENTION:  Thus set trace flags will be ADDED to the regular
1268 ///             posting flags.
1269 
1270 NCBI_XNCBI_EXPORT
1271 extern TDiagPostFlags SetDiagTraceAllFlags(TDiagPostFlags flags);
1272 
1273 NCBI_XNCBI_EXPORT
1274 extern void SetDiagTraceFlag(EDiagPostFlag flag);
1275 
1276 NCBI_XNCBI_EXPORT
1277 extern void UnsetDiagTraceFlag(EDiagPostFlag flag);
1278 
1279 class CDiagContextThreadData;
1280 
1281 /// Guard for collecting diag messages (affects the current thread only).
1282 ///
1283 /// Messages with the severity equal or above 'print' severity will be
1284 /// printed but not collected. Messages having severity below 'print'
1285 /// severity and equal or above 'collect' severity will be collected,
1286 /// and later can be either discarded or printed out upon the guard
1287 /// destruction or when Release() is called.
1288 /// @note
1289 ///  Nested guards are allowed. Each guard takes care to restore the
1290 ///  severity thresholds set by the previous one.
1291 class NCBI_XNCBI_EXPORT CDiagCollectGuard
1292 {
1293 public:
1294     /// Action to perform in guard's destructor
1295     enum EAction {
1296         ePrint,   ///< Print all collected messages
1297         eDiscard  ///< Discard collected messages, default
1298     };
1299 
1300     /// Set collectable severity to the current post level,
1301     /// print severity is set to critical.
1302     /// The default action is eDiscard.
1303     CDiagCollectGuard(void);
1304 
1305     /// Set collectable severity to the current post level,
1306     /// print severity is set to the specified value but can be ignored
1307     /// if it's lower than the currently set post level (or print severity
1308     /// set by a higher level guard).
1309     /// The default action is eDiscard.
1310     CDiagCollectGuard(EDiagSev print_severity);
1311 
1312     /// Create diag collect guard with the given severities and action.
1313     /// The guard will not set print severity below the current diag
1314     /// post level (or print severity of a higher level guard).
1315     /// Collect severity should be equal or lower than the current
1316     /// diag post level or collect severity.
1317     /// The default action is eDiscard.
1318     CDiagCollectGuard(EDiagSev print_severity,
1319                       EDiagSev collect_severity,
1320                       EAction  action = eDiscard);
1321 
1322     /// Destroy the guard, return post level to the one set before the
1323     /// guard initialization. Depending on the currently set action
1324     /// print or discard the messages.
1325     /// On ePrint all collected messages are printed (if there is no
1326     /// higher level guard) and removed from the collection.
1327     /// On eDiscard the messages are silently discarded (only when the
1328     /// last of several nested guards is destroyed).
1329     ~CDiagCollectGuard(void);
1330 
1331     /// Get current print severity
GetPrintSeverity(void) const1332     EDiagSev GetPrintSeverity(void) const { return m_PrintSev; }
1333     /// Set new print severity. The new print severity can not be
1334     /// lower than the current one.
1335     void SetPrintSeverity(EDiagSev sev);
1336 
1337     /// Get current collect severity
GetCollectSeverity(void) const1338     EDiagSev GetCollectSeverity(void) const { return m_CollectSev; }
1339     /// Set new collect severity. The new collect severity can not be
1340     /// higher than the current one.
1341     void SetCollectSeverity(EDiagSev sev);
1342 
1343     /// Get selected on-destroy action
GetAction(void) const1344     EAction GetAction(void) const { return m_Action; }
1345     /// Specify on-destroy action.
SetAction(EAction action)1346     void SetAction(EAction action) { m_Action = action; }
1347 
1348     /// Release the guard. Perform the currently set action, stop collecting
1349     /// messages, reset severities set by this guard.
1350     void Release(void);
1351 
1352     /// Release the guard. Perform the specified action, stop collecting
1353     /// messages, reset severities set by this guard.
1354     void Release(EAction action);
1355 
1356 private:
1357     void x_Init(EDiagSev print_severity,
1358                 EDiagSev collect_severity,
1359                 EAction  action);
1360 
1361     EDiagSev           m_PrintSev;
1362     EDiagSev           m_CollectSev;
1363     EAction            m_Action;
1364 };
1365 
1366 
1367 /// Specify a string to prefix all subsequent error postings with.
1368 NCBI_XNCBI_EXPORT
1369 extern void SetDiagPostPrefix(const char* prefix);
1370 
1371 /// Push a string to the list of message prefixes.
1372 NCBI_XNCBI_EXPORT
1373 extern void PushDiagPostPrefix(const char* prefix);
1374 
1375 /// Pop a string from the list of message prefixes.
1376 NCBI_XNCBI_EXPORT
1377 extern void PopDiagPostPrefix(void);
1378 
1379 /// Get iteration number/request ID.
1380 NCBI_XNCBI_EXPORT
1381 extern Uint8 GetDiagRequestId(void);
1382 
1383 /// Set iteration number/request ID.
1384 NCBI_XNCBI_EXPORT
1385 extern void SetDiagRequestId(Uint8 id);
1386 
1387 
1388 NCBI_DEPRECATED
GetFastCGIIteration(void)1389 inline Uint8 GetFastCGIIteration(void)
1390 {
1391     return GetDiagRequestId();
1392 }
1393 
1394 
1395 NCBI_DEPRECATED
SetFastCGIIteration(Uint8 id)1396 inline void SetFastCGIIteration(Uint8 id)
1397 {
1398     SetDiagRequestId(id);
1399 }
1400 
1401 
1402 /////////////////////////////////////////////////////////////////////////////
1403 ///
1404 /// CDiagAutoPrefix --
1405 ///
1406 /// Define the auxiliary class to temporarily add a prefix.
1407 
1408 class NCBI_XNCBI_EXPORT CDiagAutoPrefix
1409 {
1410 public:
1411     /// Constructor.
1412     CDiagAutoPrefix(const string& prefix);
1413 
1414     /// Constructor.
1415     CDiagAutoPrefix(const char*   prefix);
1416 
1417     /// Remove the prefix automagically, when the object gets out of scope.
1418     ~CDiagAutoPrefix(void);
1419 };
1420 
1421 
1422 /// Diagnostic post severity level.
1423 ///
1424 /// The value of DIAG_POST_LEVEL can be a digital value (0-9) or
1425 /// string value from CDiagBuffer::sm_SeverityName[].
1426 #define DIAG_POST_LEVEL "DIAG_POST_LEVEL"
1427 
1428 /// Set the threshold severity for posting the messages.
1429 ///
1430 /// This function has effect only if:
1431 ///   - Environment variable $DIAG_POST_LEVEL is not set, and
1432 ///   - Registry value of DIAG_POST_LEVEL, section DEBUG is not set
1433 ///
1434 /// Another way to do filtering is to call SetDiagFilter
1435 ///
1436 /// @param  post_sev
1437 ///   Post only messages with severity greater or equal to "post_sev".
1438 ///
1439 ///   Special case:  eDiag_Trace -- print all messages and turn on the tracing.
1440 /// @return
1441 ///   Return previous post-level.
1442 /// @sa SetDiagFilter(), SetDiagTrace()
1443 NCBI_XNCBI_EXPORT
1444 extern EDiagSev SetDiagPostLevel(EDiagSev post_sev = eDiag_Error);
1445 
1446 /// Get current threshold severity for posting the messages.
1447 /// @return
1448 ///   Return current post-level.
1449 /// @sa SetDiagPostLevel()
1450 NCBI_XNCBI_EXPORT
1451 extern EDiagSev GetDiagPostLevel(void);
1452 
1453 /// Compare two severities.
1454 /// @return
1455 ///   The return value is negative if the first value is lower than
1456 /// the second one, positive if it's higher than the second one,
1457 /// 0 if the severities are equal.
1458 NCBI_XNCBI_EXPORT
1459 extern int CompareDiagPostLevel(EDiagSev sev1, EDiagSev sev2);
1460 
1461 /// Check if the specified severity is higher or equal to the currently
1462 /// selected post level and will be printed by ERR_POST.
1463 NCBI_XNCBI_EXPORT
1464 extern bool IsVisibleDiagPostLevel(EDiagSev sev);
1465 
1466 /// Disable change the diagnostic post level.
1467 ///
1468 /// Consecutive using SetDiagPostLevel() will not have effect.
1469 NCBI_XNCBI_EXPORT
1470 extern bool DisableDiagPostLevelChange(bool disable_change = true);
1471 
1472 /// Sets and locks the level, combining the previous two calls.
1473 NCBI_XNCBI_EXPORT
1474 extern void SetDiagFixedPostLevel(EDiagSev post_sev);
1475 
1476 /// Set the "die" (abort) level for the program.
1477 ///
1478 /// Abort the application if severity is >= "die_sev".
1479 /// Throw an exception if die_sev is not in the range
1480 /// [eDiagSevMin..eDiag_Fatal].
1481 /// @return
1482 ///   Return previous die-level.
1483 NCBI_XNCBI_EXPORT
1484 extern EDiagSev SetDiagDieLevel(EDiagSev die_sev = eDiag_Fatal);
1485 
1486 /// Get the "die" (abort) level for the program.
1487 NCBI_XNCBI_EXPORT
1488 extern EDiagSev GetDiagDieLevel(void);
1489 
1490 /// Ignore the die level settings.  Return previous setting.
1491 ///
1492 /// WARNING!!! -- not recommended for use unless you are real desperate:
1493 /// By passing TRUE to this function you can make your application
1494 /// never exit/abort regardless of the level set by SetDiagDieLevel().
1495 /// But be warned this is usually a VERY BAD thing to do!
1496 /// -- because any library code counts on at least "eDiag_Fatal" to exit
1497 /// unconditionally, and thus what happens once "eDiag_Fatal" has been posted,
1498 /// is, in general, totally unpredictable!  Therefore, use it on your own risk.
1499 NCBI_XNCBI_EXPORT
1500 extern bool IgnoreDiagDieLevel(bool ignore);
1501 
1502 /// Abort handler function type.
1503 typedef void (*FAbortHandler)(void);
1504 
1505 /// Set/unset abort handler.
1506 ///
1507 /// If "func"==0 use default handler.
1508 NCBI_XNCBI_EXPORT
1509 extern void SetAbortHandler(FAbortHandler func = 0);
1510 
1511 /// Smart abort function.
1512 ///
1513 /// Processes user abort handler and does not pop up assert windows
1514 /// if specified (environment variable DIAG_SILENT_ABORT is "Y" or "y").
1515 NCBI_NORETURN NCBI_XNCBI_EXPORT
1516 extern void Abort(void);
1517 
1518 /// Diagnostic trace setting.
1519 #define DIAG_TRACE "DIAG_TRACE"
1520 
1521 /// Which setting disables/enables posting of "eDiag_Trace" messages.
1522 ///
1523 /// By default, trace messages are disabled unless:
1524 /// - Environment variable $DIAG_TRACE is set (to any value), or
1525 /// - Registry value of DIAG_TRACE, section DEBUG is set (to any value)
1526 enum EDiagTrace {
1527     eDT_Default = 0,  ///< Restores the default tracing context
1528     eDT_Disable,      ///< Ignore messages of severity "eDiag_Trace"
1529     eDT_Enable        ///< Enable messages of severity "eDiag_Trace"
1530 };
1531 
1532 
1533 /// Set the diagnostic trace settings.
1534 NCBI_XNCBI_EXPORT
1535 extern void SetDiagTrace(EDiagTrace how, EDiagTrace dflt = eDT_Default);
1536 
1537 /// Check if traces are enabled.
1538 NCBI_XNCBI_EXPORT
1539 extern bool GetDiagTrace(void);
1540 
1541 
1542 /// Forward declarations
1543 class CTime;
1544 
1545 /// Internal structure to hold diag message string data.
1546 struct SDiagMessageData;
1547 
1548 struct SDiagMessage;
1549 
1550 /// Callback interface for stream parser. Called for every message read
1551 /// from the input stream.
1552 /// @sa SDiagMessage
1553 class INextDiagMessage
1554 {
1555 public:
1556     virtual void operator()(SDiagMessage& msg) = 0;
~INextDiagMessage(void)1557     virtual ~INextDiagMessage(void) {}
1558 };
1559 
1560 
1561 /////////////////////////////////////////////////////////////////////////////
1562 ///
1563 /// SDiagMessage --
1564 ///
1565 /// Diagnostic message structure.
1566 ///
1567 /// Defines structure of the "data" message that is used with message handler
1568 /// function("func"),  and destructor("cleanup").
1569 /// The "func(..., data)" to be called when any instance of "CNcbiDiagBuffer"
1570 /// has a new diagnostic message completed and ready to post.
1571 /// "cleanup(data)" will be called whenever this hook gets replaced and
1572 /// on the program termination.
1573 /// NOTE 1:  "func()", "cleanup()" and "g_SetDiagHandler()" calls are
1574 ///          MT-protected, so that they would never be called simultaneously
1575 ///          from different threads.
1576 /// NOTE 2:  By default, the errors will be written to standard error stream.
1577 
1578 struct NCBI_XNCBI_EXPORT SDiagMessage {
1579     typedef Uint8 TPID;   ///< Process ID
1580     typedef Uint8 TTID;   ///< Thread ID
1581     typedef Int8  TUID;   ///< Unique process ID
1582 
1583     /// Generic type for counters (posts, requests etc.)
1584     typedef Uint8 TCount;
1585 
1586     /// Initialize SDiagMessage fields.
1587     SDiagMessage(EDiagSev severity, const char* buf, size_t len,
1588                  const char* file = 0, size_t line = 0,
1589                  TDiagPostFlags flags = eDPF_Default, const char* prefix = 0,
1590                  int err_code = 0, int err_subcode = 0,
1591                  const char* err_text  = 0,
1592                  const char* module    = 0,
1593                  const char* nclass    = 0,
1594                  const char* function  = 0);
1595 
1596     /// Copy constructor required to store the messages and flush them when
1597     /// the diagnostics setup is finished.
1598     SDiagMessage(const SDiagMessage& message);
1599 
1600     /// Assignment of messages
1601     SDiagMessage& operator=(const SDiagMessage& message);
1602 
1603     /// Parse a string back into SDiagMessage. Optional bool argument is
1604     /// set to true if the message was parsed successfully.
1605     SDiagMessage(const string& message, bool* result = 0);
1606 
1607     ~SDiagMessage(void);
1608 
1609     /// Parse the whole string into the message.
1610     /// Return true on success, false if parsing failed.
1611     bool ParseMessage(const string& message);
1612 
1613     /// Stream parser. Reads messages from a stream and calls the callback
1614     /// for each message.
1615     static void ParseDiagStream(CNcbiIstream& in,
1616                                 INextDiagMessage& func);
1617 
1618     /// Type of event to report
1619     enum EEventType {
1620         eEvent_Start,        ///< Application start
1621         eEvent_Stop,         ///< Application exit
1622         eEvent_Extra,        ///< Other application events
1623         eEvent_RequestStart, ///< Start processing request
1624         eEvent_RequestStop,  ///< Finish processing request
1625         eEvent_PerfLog       ///< Performance log
1626     };
1627 
1628     static string GetEventName(EEventType event);
1629 
1630     mutable EDiagSev m_Severity;   ///< Severity level
1631     const char*      m_Buffer;     ///< Not guaranteed to be '\0'-terminated!
1632     size_t           m_BufferLen;  ///< Length of m_Buffer
1633     const char*      m_File;       ///< File name
1634     const char*      m_Module;     ///< Module name
1635     const char*      m_Class;      ///< Class name
1636     const char*      m_Function;   ///< Function name
1637     size_t           m_Line;       ///< Line number in file
1638     int              m_ErrCode;    ///< Error code
1639     int              m_ErrSubCode; ///< Sub Error code
1640     TDiagPostFlags   m_Flags;      ///< Bitwise OR of "EDiagPostFlag"
1641     const char*      m_Prefix;     ///< Prefix string
1642     const char*      m_ErrText;    ///< Sometimes 'error' has no numeric code,
1643                                    ///< but can be represented as text
1644     TPID             m_PID;        ///< Process ID
1645     TTID             m_TID;        ///< Thread ID
1646     TCount           m_ProcPost;   ///< Number of the post in the process
1647     TCount           m_ThrPost;    ///< Number of the post in the thread
1648     TCount           m_RequestId;  ///< FastCGI iteration or request ID
1649 
1650     /// If the severity is eDPF_AppLog, m_Event contains event type.
1651     EEventType       m_Event;
1652 
1653     typedef pair<string, string> TExtraArg;
1654     typedef list<TExtraArg>      TExtraArgs;
1655 
1656     /// If event type is "extra", contains the list of arguments
1657     TExtraArgs       m_ExtraArgs;
1658     /// Set to true if this is a typed extra message (the arguments include
1659     /// "NCBIEXTRATYPE=<extra-type>").
1660     bool             m_TypedExtra;
1661 
1662     /// Special flag indicating that the message should not be printed by
1663     /// Tee-handler.
1664     bool             m_NoTee;
1665 
1666     bool m_PrintStackTrace; // Print stack trace after the message
1667 
1668     /// Convert extra arguments to string
1669     string FormatExtraMessage(void) const;
1670 
1671     /// Get UID from current context or parsed from a string
1672     TUID GetUID(void) const;
1673     /// Get time and date - current or parsed.
1674     CTime GetTime(void) const;
1675 
1676     /// Compose a message string in the standard format(see also "flags"):
1677     ///    "<file>", line <line>: <severity>: [<prefix>] <message> [EOL]
1678     /// and put it to string "str", or write to an output stream "os".
1679 
1680     /// Which write flags should be output in diagnostic message.
1681     enum EDiagWriteFlags {
1682         fNone     = 0x0,      ///< No flags
1683         fNoEndl   = 0x01,     ///< No end of line
1684         fNoPrefix = 0x02      ///< No std prefix
1685     };
1686 
1687     typedef int TDiagWriteFlags; /// Binary OR of "EDiagWriteFlags"
1688 
1689     /// Write to string.
1690     void Write(string& str, TDiagWriteFlags flags = fNone) const;
1691 
1692     /// Write to stream.
1693     CNcbiOstream& Write  (CNcbiOstream& os, TDiagWriteFlags fl = fNone) const;
1694 
1695     /// Access to strings stored in SDiagMessageData.
1696     const string& GetHost(void) const;
1697     const string& GetClient(void) const;
1698     string GetSession(void) const;
1699     const string& GetAppName(void) const;
1700     EDiagAppState GetAppState(void) const;
1701 
1702     CNcbiOstream& x_OldWrite(CNcbiOstream& os, TDiagWriteFlags fl = fNone) const;
1703     CNcbiOstream& x_NewWrite(CNcbiOstream& os, TDiagWriteFlags fl = fNone) const;
1704     string x_GetModule(void) const;
1705 
1706     static void s_EscapeNewlines(string& buf);
1707     static void s_UnescapeNewlines(string& buf);
1708 
1709 private:
1710     // Parse extra args formatted as CGI query string. Do not check validity
1711     // of names and values. Split args by '&', split name/value by '=', do
1712     // URL-decoding.
1713     // If the string is not in the correct format (no '&' or '=') do not
1714     // parse it, return false.
1715     bool x_ParseExtraArgs(const string& str, size_t pos);
1716 
1717     enum EFormatFlag {
1718         eFormat_Old,  // Force old post format
1719         eFormat_New,  // Force new post format
1720         eFormat_Auto  // Get post format from CDiagContext, default
1721     };
x_SetFormatSDiagMessage1722     void x_SetFormat(EFormatFlag fmt) const { m_Format = fmt; }
1723     bool x_IsSetOldFormat(void) const;
1724     friend class CDiagContext;
1725 
1726     // Initialize data with the current values
1727     void x_InitData(void) const;
1728     // Save current context properties
1729     void x_SaveContextData(void) const;
1730 
1731     mutable SDiagMessageData* m_Data;
1732     mutable EFormatFlag       m_Format;
1733 
1734     // Flag indicating if bad symbols in extra argument names are allowed.
1735     // The flag can be set only by CDiagContext_Extra.
1736     friend class CDiagContext_Extra;
1737     bool m_AllowBadExtraNames;
1738 };
1739 
1740 /// Insert message in output stream.
operator <<(CNcbiOstream & os,const SDiagMessage & mess)1741 inline CNcbiOstream& operator<< (CNcbiOstream& os, const SDiagMessage& mess) {
1742     return mess.Write(os);
1743 }
1744 
1745 
1746 
1747 /////////////////////////////////////////////////////////////////////////////
1748 ///
1749 /// CDiagContext --
1750 ///
1751 /// NCBI diagnostic context. Storage for application-wide properties.
1752 
1753 class CSpinLock;
1754 class CStopWatch;
1755 class CDiagHandler;
1756 class CNcbiRegistry;
1757 
1758 /// Where to write the application's diagnostics to.
1759 enum EAppDiagStream {
1760     eDS_ToStdout,    ///< To standard output stream
1761     eDS_ToStderr,    ///< To standard error stream
1762     eDS_ToStdlog,    ///< Try standard log file (app.name + ".log") in /log/
1763                      ///< and current directory, use stderr if both fail.
1764     eDS_ToMemory,    ///< Keep in a temp.memory buffer, see FlushMessages()
1765     eDS_Disable,     ///< Don't write it anywhere
1766     eDS_User,        ///< Leave as was previously set (or not set) by user
1767     eDS_AppSpecific, ///< Call the application's SetupDiag_AppSpecific()
1768                      ///< @deprecated
1769     eDS_Default,     ///< Try standard log file (app.name + ".log") in /log/,
1770                      ///< use stderr on failure.
1771     eDS_ToSyslog     ///< To system log daemon
1772 };
1773 
1774 
1775 /// Flags to control collecting messages and flushing them to the new
1776 /// destination when switching diag handlers.
1777 enum EDiagCollectMessages {
1778     eDCM_Init,        ///< Start collecting messages (with limit), do nothing
1779                       ///< if already initialized.
1780     eDCM_InitNoLimit, ///< Start collecting messages without limit (must stop
1781                       ///< collecting later using eDCM_Flush or eDCM_Discard).
1782     eDCM_NoChange,    ///< Continue collecting messages if already started.
1783     eDCM_Flush,       ///< Flush the collected messages and stop collecting.
1784     eDCM_Discard      ///< Discard the collected messages without flushing.
1785 };
1786 
1787 
1788 /// Post number increment flag for GetProcessPostNumber() and
1789 /// GetThreadPostNumber().
1790 enum EPostNumberIncrement {
1791     ePostNumber_NoIncrement,  ///< Get post number without incrementing it
1792     ePostNumber_Increment     ///< Increment and return the new post number
1793 };
1794 
1795 
1796 struct SRequestCtxWrapper;
1797 class CRequestContext;
1798 class CSharedHitId;
1799 class CRequestRateControl;
1800 class CEncodedString;
1801 
1802 
1803 /// Thread local context data stored in TLS
1804 class NCBI_XNCBI_EXPORT CDiagContextThreadData
1805 {
1806 public:
1807     CDiagContextThreadData(void);
1808     ~CDiagContextThreadData(void);
1809 
1810     /// Get current request context.
1811     CRequestContext& GetRequestContext(void);
1812     /// Set request context. If NULL, switches the current thread
1813     /// to its default request context.
1814     void SetRequestContext(CRequestContext* ctx);
1815 
1816     /// CDiagContext properties
1817     typedef map<string, string> TProperties;
1818     enum EGetProperties {
1819         eProp_Get,    ///< Do not create properties if not exist yet
1820         eProp_Create  ///< Auto-create properties if not exist
1821     };
1822     NCBI_DEPRECATED TProperties* GetProperties(EGetProperties flag);
1823 
1824     typedef SDiagMessage::TCount TCount;
1825 
1826     /// Request id
1827     NCBI_DEPRECATED TCount GetRequestId(void);
1828     NCBI_DEPRECATED void SetRequestId(TCount id);
1829     NCBI_DEPRECATED void IncRequestId(void);
1830 
1831     /// Get request timer, create if not exist yet
GetOrCreateStopWatch(void)1832     NCBI_DEPRECATED CStopWatch* GetOrCreateStopWatch(void) { return NULL; }
1833     /// Get request timer or null
GetStopWatch(void)1834     NCBI_DEPRECATED CStopWatch* GetStopWatch(void) { return NULL; }
1835     /// Delete request timer
ResetStopWatch(void)1836     NCBI_DEPRECATED void ResetStopWatch(void) {}
1837 
1838     /// Diag buffer
GetDiagBuffer(void)1839     CDiagBuffer& GetDiagBuffer(void) { return *m_DiagBuffer; }
1840 
1841     /// Get diag context data for the current thread
1842     static CDiagContextThreadData& GetThreadData(void);
1843 
1844     /// Thread ID
1845     typedef Uint8 TTID;
1846 
1847     /// Get cached thread ID
GetTID(void) const1848     TTID GetTID(void) const { return m_TID; }
1849 
1850     /// Get thread post number
1851     TCount GetThreadPostNumber(EPostNumberIncrement inc);
1852 
1853     void AddCollectGuard(CDiagCollectGuard* guard);
1854     void RemoveCollectGuard(CDiagCollectGuard* guard);
1855     CDiagCollectGuard* GetCollectGuard(void);
1856 
1857     void CollectDiagMessage(const SDiagMessage& mess);
1858 
1859     static bool IsInitialized(void);
1860 
1861 private:
1862     CDiagContextThreadData(const CDiagContextThreadData&);
1863     CDiagContextThreadData& operator=(const CDiagContextThreadData&);
1864 
1865     // Guards override the global post level and define severity
1866     // for collecting messages.
1867     typedef list<CDiagCollectGuard*> TCollectGuards;
1868 
1869     // Collected diag messages
1870     typedef list<SDiagMessage>       TDiagCollection;
1871 
1872     unique_ptr<TProperties> m_Properties;       // Per-thread properties
1873     unique_ptr<CDiagBuffer> m_DiagBuffer;       // Thread's diag buffer
1874     TTID                  m_TID;              // Cached thread ID
1875     TCount                m_ThreadPostNumber; // Number of posted messages
1876     TCollectGuards        m_CollectGuards;
1877     TDiagCollection       m_DiagCollection;
1878     size_t                m_DiagCollectionSize; // cached size of m_DiagCollection
1879     unique_ptr<SRequestCtxWrapper> m_RequestCtx;        // Request context
1880     unique_ptr<SRequestCtxWrapper> m_DefaultRequestCtx; // Default request context
1881 };
1882 
1883 
1884 template<class TKey, class TStorage> class CStrictId;
1885 
1886 /// Temporary object for holding extra message arguments. Prints all
1887 /// of the arguments on destruction.
1888 class NCBI_XNCBI_EXPORT CDiagContext_Extra
1889 {
1890 public:
1891     /// Prints all arguments as "name1=value1&name2=value2...".
1892     ~CDiagContext_Extra(void);
1893 
1894     /// The method does not print the argument, but adds it to the string.
1895     /// Name must contain only alphanumeric chars or '_'.
1896     /// Value is URL-encoded before printing.
1897     CDiagContext_Extra& Print(const string& name, const string& value);
1898 
1899     /// Overloaded Print() for all types.
1900     CDiagContext_Extra& Print(const string& name, const char* value);
1901     CDiagContext_Extra& Print(const string& name, int value);
1902     CDiagContext_Extra& Print(const string& name, unsigned int value);
1903     CDiagContext_Extra& Print(const string& name, long value);
1904     CDiagContext_Extra& Print(const string& name, unsigned long value);
1905 #if !NCBI_INT8_IS_LONG
1906     CDiagContext_Extra& Print(const string& name, Int8 value);
1907     CDiagContext_Extra& Print(const string& name, Uint8 value);
1908 #elif SIZEOF_LONG_LONG
1909     CDiagContext_Extra& Print(const string& name, long long value);
1910     CDiagContext_Extra& Print(const string& name, unsigned long long value);
1911 #endif
1912     CDiagContext_Extra& Print(const string& name, char value);
1913     CDiagContext_Extra& Print(const string& name, signed char value);
1914     CDiagContext_Extra& Print(const string& name, unsigned char value);
1915     CDiagContext_Extra& Print(const string& name, double value);
1916     CDiagContext_Extra& Print(const string& name, bool value);
1917     template<class TKey, class TStorage>
Print(const string & name,const CStrictId<TKey,TStorage> & value)1918     CDiagContext_Extra& Print(const string& name, const CStrictId<TKey, TStorage>& value)
1919     {
1920         return Print(name, value.Get());
1921     }
1922 
1923 
1924     typedef SDiagMessage::TExtraArg  TExtraArg;
1925     typedef SDiagMessage::TExtraArgs TExtraArgs;
1926 
1927     /// The method does not print the arguments, but adds it to the string.
1928     /// Name must contain only alphanumeric chars or '_'.
1929     /// Value is URL-encoded before printing.
1930     /// The args will be modified (emptied) by the function.
1931     CDiagContext_Extra& Print(TExtraArgs& args);
1932 
1933     /// Copying the object will prevent printing it on destruction.
1934     /// The new copy should take care of printing.
1935     CDiagContext_Extra(const CDiagContext_Extra& args);
1936     CDiagContext_Extra& operator=(const CDiagContext_Extra& args);
1937 
1938     /// Print the message and reset object. The object can then be
1939     /// reused to print a new log line (with a new set of arguments
1940     /// if necessary). This is only possible with 'extra' messages,
1941     /// request start/stop messages can not be reused after flush
1942     /// and will print error message instead.
1943     void Flush(void);
1944 
1945     /// Set extra message type.
1946     CDiagContext_Extra& SetType(const string& type);
1947 
1948     /// Allow bad symbols in argument names. URL-encode names the same way
1949     /// as values.
1950     /// NOTE: Avoid using this method if possible. Argument names with
1951     /// encoded symbols may be incompatible with some logging tools.
1952     /// If the flag is not set, any bad symbol is replaced with
1953     /// [ILLEGAL_APPLOG_SYMBOL:%##] string, where %## is the URL-encoded
1954     /// symbol.
1955     CDiagContext_Extra& AllowBadSymbolsInArgNames(void);
1956 
1957 private:
1958     void x_Release(void);
1959     bool x_CanPrint(void);
1960 
1961     // Can be created only by CDiagContext.
1962     CDiagContext_Extra(SDiagMessage::EEventType event_type);
1963     // Initialize performance log entry.
1964     CDiagContext_Extra(int         status,
1965                        double      timespan,
1966                        TExtraArgs& args);
1967 
1968     // If available, add ncbi_role/ncbi_location to the arguments.
1969     CDiagContext_Extra& PrintNcbiRoleAndLocation(void);
1970     CDiagContext_Extra& PrintNcbiAppInfoOnStart(void);
1971     CDiagContext_Extra& PrintNcbiAppInfoOnRequest(void);
1972 
1973     friend class CDiagContext;
1974     friend NCBI_XNCBI_EXPORT
1975         CDiagContext_Extra g_PostPerf(int                       status,
1976                                       double                    timespan,
1977                                       SDiagMessage::TExtraArgs& args);
1978 
1979     SDiagMessage::EEventType m_EventType;
1980     TExtraArgs*              m_Args;
1981     int*                     m_Counter;
1982     bool                     m_Typed;
1983     // PerfLog data
1984     int                      m_PerfStatus;
1985     double                   m_PerfTime;
1986     bool                     m_Flushed;
1987     bool                     m_AllowBadNames;
1988 };
1989 
1990 
1991 class NCBI_XNCBI_EXPORT CDiagContext
1992 {
1993 public:
1994     CDiagContext(void);
1995     ~CDiagContext(void);
1996 
1997     typedef Uint8 TPID;
1998     /// Get cached PID (read real PID if not cached yet).
1999     static TPID GetPID(void);
2000     /// Reset PID cache (e.g. after fork). Return true if PID was updated
2001     /// (in the child process).
2002     static bool UpdatePID(void);
2003 
2004     /// Actions to perform in UpdateOnFork().
2005     enum FOnForkAction {
2006         fOnFork_PrintStart = 1 << 0,   ///< Log app-start.
2007         fOnFork_ResetTimer = 1 << 1    ///< Reset execution timer.
2008     };
2009     typedef int TOnForkFlags;
2010 
2011     /// Update diagnostics after fork(). Updates PID if necessary (in the
2012     /// child process). If PID has not changed (parent process), no other
2013     /// actions are performed. For this reason the method will not do anything
2014     /// after the first call, since no PID changes will be detected.
2015     static void UpdateOnFork(TOnForkFlags flags);
2016 
2017     typedef SDiagMessage::TUID TUID;
2018 
2019     /// Return (create if not created yet) unique diagnostic ID.
2020     TUID GetUID(void) const;
2021     /// Return string representation of UID.
2022     /// If the argument UID is 0, use the one from the diag context.
2023     string GetStringUID(TUID uid = 0) const;
2024     /// Take the source UID and replace its timestamp part with the
2025     /// current time.
2026     /// If the source UID is 0, use the one from the diag context.
2027     TUID UpdateUID(TUID uid = 0) const;
2028     /// Fill buffer with string representation of UID. The buffer size
2029     /// must be at least 17 bytes.
2030     void GetStringUID(TUID uid, char* buf) const;
2031 
2032     /// Create global unique request id.
2033     string GetNextHitID(void) const;
2034     /// Deprecated version of HID generator.
2035     NCBI_DEPRECATED
GetGlobalRequestId(void) const2036     string GetGlobalRequestId(void) const { return GetNextHitID(); }
2037 
2038     /// Shortcut to
2039     ///   CDiagContextThreadData::GetThreadData().GetRequestContext()
2040     static CRequestContext& GetRequestContext(void);
2041     /// Shortcut to
2042     ///   CDiagContextThreadData::GetThreadData().SetRequestContext()
2043     static void SetRequestContext(CRequestContext* ctx);
2044 
2045     /// Set AutoWrite flag. If set, each property is posted to the current
2046     /// app-log stream when a new value is set.
2047     /// @deprecated
2048     NCBI_DEPRECATED
2049     void SetAutoWrite(bool value);
2050 
2051     /// Property visibility flag.
2052     /// @deprecated
2053     enum EPropertyMode {
2054         eProp_Default,  ///< Auto-mode for known properties, local for others
2055         eProp_Global,   ///< The property is global for the application
2056         eProp_Thread    ///< The property has separate value in each thread
2057     };
2058 
2059     /// Set application context property by name.
2060     /// Write property to the log if AutoPrint flag is set.
2061     /// Property mode defines if the property is a global or a
2062     /// per-thread one. By default unknown properties are set as
2063     /// thread-local.
2064     /// @deprecated
2065     NCBI_DEPRECATED
2066     void SetProperty(const string& name,
2067                      const string& value,
2068                      EPropertyMode mode = eProp_Default);
2069 
2070     /// Get application context property by name, return empty string if the
2071     /// property is not set. If mode is eProp_Default and the property is
2072     /// not a known one, check thread-local properties first.
2073     /// @deprecated
2074     NCBI_DEPRECATED
2075     string GetProperty(const string& name,
2076                        EPropertyMode mode = eProp_Default) const;
2077 
2078     /// Delete a property by name. If mode is eProp_Default and the property
2079     /// is not a known one, check thread-local properties first.
2080     /// @deprecated
2081     NCBI_DEPRECATED
2082     void DeleteProperty(const string& name,
2083                         EPropertyMode mode = eProp_Default);
2084 
2085     /// Forced dump of all set properties.
2086     /// @deprecated
2087     NCBI_DEPRECATED
2088     void PrintProperties(void);
2089 
2090     /// Global properties
2091     static const char* kProperty_UserName;
2092     static const char* kProperty_HostName;
2093     static const char* kProperty_HostIP;
2094     static const char* kProperty_AppName;
2095     static const char* kProperty_ExitSig;
2096     static const char* kProperty_ExitCode;
2097     /// Per-thread properties
2098     static const char* kProperty_AppState;
2099     static const char* kProperty_ClientIP;
2100     static const char* kProperty_SessionID;
2101     static const char* kProperty_ReqStatus;
2102     static const char* kProperty_ReqTime;
2103     static const char* kProperty_BytesRd;
2104     static const char* kProperty_BytesWr;
2105 
2106     /// Print start/stop etc. message. If the following values are set as
2107     /// properties, they will be dumped before the message:
2108     ///   host | host_ip_addr
2109     ///   client_ip
2110     ///   session_id
2111     ///   app_name
2112     /// All messages have the following prefix:
2113     ///   PID/TID/ITER UID TIME HOST CLIENT SESSION_ID APP_NAME
2114     /// Depending on its type, a message can be prefixed with the following
2115     /// properties if they are set:
2116     ///   start
2117     ///   stop [SIG] [EXIT_CODE] ELAPSED_TIME
2118     ///   extra
2119     ///   request-start
2120     ///   request-stop [STATUS] [REQ_ELAPSED_TIME] [BYTES_RD] [BYTES_WR]
2121     void PrintStart(const string& message);
2122 
2123     /// Print exit message.
2124     void PrintStop(void);
2125 
2126     /// Print extra message in plain text format.
2127     /// This method is deprecated and should be replaced by a call to
2128     /// Extra() method and one or more calls to CDiagContext_Extra::Print().
2129     NCBI_DEPRECATED void PrintExtra(const string& message);
2130 
2131     /// Create a temporary CDiagContext_Extra object. The object will print
2132     /// arguments automatically from destructor. Can be used like:
2133     ///   Extra().Print(name1, val1).Print(name2, val2);
Extra(void) const2134     CDiagContext_Extra Extra(void) const
2135     {
2136         return CDiagContext_Extra(SDiagMessage::eEvent_Extra);
2137     }
2138 
2139     /// Print request start message (for request-driven applications)
2140     /// @deprecated Use CDiagContext_Extra version.
2141     NCBI_DEPRECATED void PrintRequestStart(const string& message);
2142     /// Create a temporary CDiagContext_Extra object. The object will print
2143     /// arguments automatically from destructor. Can be used like:
2144     ///   PrintRequestStart().Print(name1, val1).Print(name2, val2);
2145     CDiagContext_Extra PrintRequestStart(void);
2146 
2147     /// Print request stop message (for request-driven applications)
2148     void PrintRequestStop(void);
2149 
2150     /// Always returns global application state.
2151     EDiagAppState GetGlobalAppState(void) const;
2152     /// Set global application state.
2153     /// Do not change state of the current thread.
2154     void SetGlobalAppState(EDiagAppState state);
2155     /// Return application state for the current thread if it's set.
2156     /// If not set, return global application state. This is a shortcut
2157     /// to the current request context's GetAppState().
2158     EDiagAppState GetAppState(void) const;
2159     /// Set application state. Application state is set globally and the
2160     /// thread's state is reset (for the current thread only).
2161     /// Request states are set for the current thread (request context) only.
2162     void SetAppState(EDiagAppState state);
2163     /// The 'mode' flag is deprecated. Use CRequestContext::SetAppState() for
2164     /// per-thread/per-request state.
2165     NCBI_DEPRECATED
2166     void SetAppState(EDiagAppState state, EPropertyMode mode);
2167 
2168     /// Check old/new format flag (for compatibility only)
2169     static bool IsSetOldPostFormat(void);
2170     /// Set old/new format flag
2171     static void SetOldPostFormat(bool value);
2172 
2173     /// Check if system TID is printed instead of CThread::GetSelf()
2174     static bool IsUsingSystemThreadId(void);
2175     /// Switch printing system TID (rather than CThread::GetSelf()) on/off
2176     static void UseSystemThreadId(bool value = true);
2177 
2178     /// Get username
2179     const string& GetUsername(void) const;
2180     /// Set username
2181     /// @sa SetDiagUserAndHost
2182     void SetUsername(const string& username);
2183 
2184     /// Get host name. The order is: cached hostname, cached hostIP,
2185     /// uname or COMPUTERNAME, SERVER_ADDR, empty string.
2186     const string& GetHost(void) const;
2187     /// URL-encoded version of GetHost()
2188     const string& GetEncodedHost(void) const;
2189 
2190     /// Get cached hostname - do not try to detect host name as GetHost() does.
2191     const string& GetHostname(void) const;
2192     /// Get URL-encoded hostname
2193     const string& GetEncodedHostname(void) const;
2194     /// Set hostname
2195     /// @sa SetDiagUserAndHost
2196     void SetHostname(const string& hostname);
2197 
2198     /// Get host IP address
GetHostIP(void) const2199     const string& GetHostIP(void) const { return m_HostIP; }
2200     /// Set host IP address
2201     void SetHostIP(const string& ip);
2202 
2203     /// Get application name
2204     const string& GetAppName(void) const;
2205     /// Get URL-encoded application name
2206     const string& GetEncodedAppName(void) const;
2207     /// Set application name
2208     void SetAppName(const string& app_name);
2209 
2210     /// Check if exit code has been set.
IsSetExitCode(void) const2211     bool IsSetExitCode(void) const { return m_ExitCodeSet; }
2212     /// Get exit code
GetExitCode(void) const2213     int GetExitCode(void) const { return m_ExitCode; }
2214     /// Set exit code
SetExitCode(int exit_code)2215     void SetExitCode(int exit_code)
2216     {
2217         m_ExitCode = exit_code;
2218         m_ExitCodeSet = true;
2219     }
2220 
2221     /// Get exit signal
GetExitSignal(void) const2222     int GetExitSignal(void) const { return m_ExitSig; }
2223     /// Set exit signal
SetExitSignal(int exit_sig)2224     void SetExitSignal(int exit_sig) { m_ExitSig = exit_sig; }
2225 
2226     /// Get default session id. The session id may be set using
2227     /// SetDefaultSessionId(), NCBI_LOG_SESSION_ID env. variable
2228     /// or Log.Session_Id value in the INI file.
2229     string GetDefaultSessionID(void) const;
2230     /// Set new default session id. This value is used only if the per-request
2231     /// session id is not set.
2232     void SetDefaultSessionID(const string& session_id);
2233     /// Get the effective session id: the per-request session id if set,
2234     /// or the default session id.
2235     string GetSessionID(void) const;
2236     /// Get url-encoded session id.
2237     string GetEncodedSessionID(void) const;
2238 
2239     /// Get default client ip. The ip may be set using SetDefaultClientIP(),
2240     /// NCBI_LOG_CLIENT_IP env. variable or Log.Client_Ip value in the INI
2241     /// file.
2242     static const string GetDefaultClientIP(void);
2243     /// Set new default client ip. This value is used only if by the time
2244     /// 'request start' is logged there's no explicit ip set in the current
2245     /// request context.
2246     static void SetDefaultClientIP(const string& client_ip);
2247 
2248     /// Get global default hit id. The hit id may be set using
2249     /// SetDefaultHitId(), HTTP_NCBI_PHID or NCBI_LOG_HIT_ID env. variables,
2250     /// or Log.Http_Hit_Id/Log.Hit_Id values in the INI file. The Http-value
2251     /// has higher priority. If none of the values is set, the default hit id
2252     /// is generated automatically.
2253     string GetDefaultHitID(void) const;
2254 
2255     /// Set new global default hit id. This value is used only if the per-request
2256     /// hit id is not set.
2257     void SetDefaultHitID(const string& hit_id);
2258 
2259     /// Get host role (DEV/QA/TRY/PROD) from /etc/ncbi/role.
2260     static const string& GetHostRole(void);
2261 
2262     /// Get host location (be-md/st-va) from /etc/ncbi/location.
2263     static const string& GetHostLocation(void);
2264 
2265     /// Write standard prefix to the stream. Use values from the message
2266     /// (PID/TID/RID etc.).
2267     void WriteStdPrefix(CNcbiOstream& ostr,
2268                         const SDiagMessage& msg) const;
2269 
2270     /// Start collecting all messages (the collected messages can be flushed
2271     /// to a new destination later). Stop collecting messages when max_size
2272     /// is reached.
2273     void InitMessages(size_t max_size = 100);
2274     /// Save new message
2275     void PushMessage(const SDiagMessage& message);
2276     /// Flush the collected messages to the current diag handler.
2277     /// Does not clear the collected messages.
2278     void FlushMessages(CDiagHandler& handler);
2279     /// Discard the collected messages without printing them.
2280     void DiscardMessages(void);
2281     /// Check if message collecting is on
IsCollectingMessages(void) const2282     bool IsCollectingMessages(void) const { return m_Messages.get() != 0; }
2283 
2284     /// Get log file truncation flag
2285     static bool GetLogTruncate(void);
2286     /// Set log file truncation flag
2287     static void SetLogTruncate(bool value);
2288 
2289     /// @depracated The flag is always set now, the funcion still calls
2290     /// SetupDiag() for compatibility, but has no other effects.
2291     NCBI_DEPRECATED static void SetUseRootLog(void);
2292 
2293     /// Check if the current diagnostics destination is /log/*
2294     static bool IsUsingRootLog(void);
2295 
2296     /// Application-wide diagnostics setup. Attempts to create log files
2297     /// or diag streams according to the 'ds' flag. If 'config' is set,
2298     /// gets name of the log file from the registry.
2299     static void SetupDiag(EAppDiagStream       ds = eDS_Default,
2300                           CNcbiRegistry*       config = NULL,
2301                           EDiagCollectMessages collect = eDCM_NoChange,
2302                           const char*          cmd_logfile = NULL);
2303 
2304     typedef SDiagMessage::TCount TCount;
2305     /// Return process post number (incrementing depends on the flag).
2306     static TCount GetProcessPostNumber(EPostNumberIncrement inc);
2307 
2308     /// Type of logging rate limit
2309     enum ELogRate_Type {
2310         eLogRate_App,   ///< Application log
2311         eLogRate_Err,   ///< Error log
2312         eLogRate_Trace  ///< Trace log
2313     };
2314 
2315     /// Logging rate control - max number of messages per period.
2316     unsigned int GetLogRate_Limit(ELogRate_Type type) const;
2317     void         SetLogRate_Limit(ELogRate_Type type, unsigned int limit);
2318 
2319     /// Logging rate control - the messages control period, seconds.
2320     unsigned int GetLogRate_Period(ELogRate_Type type) const;
2321     void SetLogRate_Period(ELogRate_Type type, unsigned int period);
2322 
2323     /// Internal function, should be used only by CNcbiApplication.
2324     static void x_FinalizeSetupDiag(void);
2325 
2326     /// When using applog, the diag post level is locked to Warning.
2327     /// The following functions allow to access the lock, but should
2328     /// not be used by most applications.
IsApplogSeverityLocked(void)2329     static bool IsApplogSeverityLocked(void)
2330         { return sm_ApplogSeverityLocked; }
SetApplogSeverityLocked(bool lock)2331     static void SetApplogSeverityLocked(bool lock)
2332         { sm_ApplogSeverityLocked = lock; }
2333 
2334 private:
2335     CDiagContext(const CDiagContext&);
2336     CDiagContext& operator=(const CDiagContext&);
2337 
2338     // Initialize UID
2339     void x_CreateUID(void) const;
2340     // Write message to the log using current handler
2341     void x_PrintMessage(SDiagMessage::EEventType event,
2342                         const string&            message);
2343     // Start request or report error if one is already running
2344     static void x_StartRequest(void);
2345     // Log environment and registry variables as an extra message.
2346     static void x_LogEnvironment(void);
2347 
2348     typedef map<string, string> TProperties;
2349     friend class CDiagContext_Extra;
2350 
2351     // Reset logging rates to the values stored in CParam-s
2352     void ResetLogRates(void);
2353 
2354     // Check message logging rate
2355     bool ApproveMessage(SDiagMessage& msg, bool* show_warning);
2356 
2357     static void sx_ThreadDataTlsCleanup(CDiagContextThreadData* value,
2358                                         void*                   cleanup_data);
2359     friend class CDiagContextThreadData;
2360     friend class CDiagBuffer;
2361     friend class CRequestContext;
2362 
2363     // Default hit id initialization flags.
2364     enum EDefaultHitIDFlags {
2365         eHitID_NoCreate, // Do not create new hit id.
2366         eHitID_Create    // Create new hit id if it's not yet set.
2367     };
2368 
2369     // Check if current state is 'PB/P/PE'.
2370     bool x_DiagAtApplicationLevel(void) const;
2371     bool x_IsSetDefaultHitID(void) const;
2372     CSharedHitId x_GetDefaultHitID(EDefaultHitIDFlags flag) const;
2373     string x_GetNextHitID(bool is_default) const;
2374     void x_LogHitID(void) const;
2375     void x_LogHitID_WithLock(void) const; // Same as above but with mutex lock.
2376 
2377     // Saved messages to be flushed after setting up log files
2378     typedef list<SDiagMessage> TMessages;
2379 
2380     // Cached process ID
2381     static TPID                         sm_PID;
2382 
2383     mutable TUID                        m_UID;
2384     mutable unique_ptr<CEncodedString>  m_Host;
2385     string                              m_HostIP;
2386     unique_ptr<CEncodedString>          m_Username;
2387     unique_ptr<CEncodedString>          m_AppName;
2388     mutable bool                        m_AppNameSet;
2389     mutable unique_ptr<CEncodedString>  m_DefaultSessionId;
2390     mutable unique_ptr<CSharedHitId>    m_DefaultHitId;
2391     mutable bool                        m_LoggedHitId;
2392     int                                 m_ExitCode;
2393     bool                                m_ExitCodeSet;
2394     int                                 m_ExitSig;
2395     EDiagAppState                       m_AppState;
2396     TProperties                         m_Properties;
2397     unique_ptr<CStopWatch>              m_StopWatch;
2398     unique_ptr<TMessages>               m_Messages;
2399     size_t                              m_MaxMessages;
2400     static CDiagContext*                sm_Instance;
2401 
2402     // Lock severity changes when using applog
2403     static bool                         sm_ApplogSeverityLocked;
2404 
2405     // Rate control
2406     unique_ptr<CRequestRateControl>     m_AppLogRC;
2407     unique_ptr<CRequestRateControl>     m_ErrLogRC;
2408     unique_ptr<CRequestRateControl>     m_TraceLogRC;
2409     atomic<bool>                        m_AppLogSuspended;
2410     atomic<bool>                        m_ErrLogSuspended;
2411     atomic<bool>                        m_TraceLogSuspended;
2412 };
2413 
2414 
2415 /// Get diag context instance
2416 NCBI_XNCBI_EXPORT CDiagContext& GetDiagContext(void);
2417 
2418 
2419 /////////////////////////////////////////////////////////////////////////////
2420 ///
2421 /// CNcbiLogFields --
2422 ///
2423 /// Automatic logging of application/request meta-data.
2424 
2425 class NCBI_XNCBI_EXPORT CNcbiLogFields
2426 {
2427 public:
2428     /// Load fields to be logged from NCBI_LOG_FIELDS environment variable.
2429     CNcbiLogFields(const string& source);
2430 
2431     ~CNcbiLogFields(void);
2432 
2433     /// Log (as an extra) all names/values matching fields in NCBI_LOG_FIELDS.
2434     /// If source passed to the constructor is not empty, all names are prefixed
2435     /// with 'source.' string.
2436     template<class TEntries>
LogFields(const TEntries & entries) const2437     void LogFields(const TEntries&   entries) const
2438     {
2439         CDiagContext_Extra extra = GetDiagContext().Extra();
2440         for (typename TEntries::const_iterator it = entries.begin(); it != entries.end(); ++it) {
2441             x_Match(it->first, it->second, extra);
2442         }
2443     }
2444 
2445 private:
2446     // Check if the name matches any NCBI_LOG_FIELDS entry, print matching values to the extra.
2447     void x_Match(const string& name, const string& value, CDiagContext_Extra& extra) const;
2448 
2449     typedef list<string> TFields;
2450 
2451     string m_Source;
2452     TFields m_Fields;
2453 };
2454 
2455 
2456 /////////////////////////////////////////////////////////////////////////////
2457 ///
2458 /// CDiagHandler --
2459 ///
2460 /// Base diagnostic handler class.
2461 
2462 /// Type of file for the output
2463 enum EDiagFileType
2464 {
2465     eDiagFile_Err,    ///< Error log file
2466     eDiagFile_Log,    ///< Access log file
2467     eDiagFile_Trace,  ///< Trace log file
2468     eDiagFile_Perf,   ///< Perf log file
2469     eDiagFile_All     ///< All log files
2470 };
2471 
2472 class NCBI_XNCBI_EXPORT CDiagHandler
2473 {
2474 public:
2475     /// Destructor.
~CDiagHandler(void)2476     virtual ~CDiagHandler(void) {}
2477 
2478     /// Post message to handler.
2479     virtual void Post(const SDiagMessage& mess) = 0;
2480     /// Post message to console regardless of its severity.
2481     virtual void PostToConsole(const SDiagMessage& mess);
2482 
2483     /// Check if the handler supports async writes.
2484     /// @sa ComposeMessage, WriteMessage
2485     virtual bool AllowAsyncWrite(const SDiagMessage& msg) const;
2486     /// Compose message without writing it. If async mode is not
2487     /// supported, return empty string.
2488     virtual string ComposeMessage(const SDiagMessage& msg,
2489                                   EDiagFileType*      file_type) const;
2490     /// Write string to the log. The string may contain multiple messages of
2491     /// the same type.
2492     virtual void WriteMessage(const char*   buf,
2493                               size_t        len,
2494                               EDiagFileType file_type);
2495 
2496     /// Get current diag posts destination
2497     virtual string GetLogName(void);
2498 
2499     enum EReopenFlags {
2500         fTruncate = 0x01,   ///< Truncate file to zero size
2501         fCheck    = 0x02,   ///< Reopen only if necessary
2502         fDefault  = 0       ///< Default reopen flags:
2503                             ///< - no truncation
2504                             ///< - do not check if necessary
2505     };
2506     typedef int TReopenFlags;
2507 
2508     /// Reopen file to enable log rotation.
Reopen(TReopenFlags)2509     virtual void Reopen(TReopenFlags /*flags*/) {}
2510 };
2511 
2512 
2513 /// Diagnostic handler function type.
2514 typedef void (*FDiagHandler)(const SDiagMessage& mess);
2515 
2516 /// Diagnostic cleanup function type.
2517 typedef void (*FDiagCleanup)(void* data);
2518 
2519 /// Set the diagnostic handler using the specified diagnostic handler class.
2520 NCBI_XNCBI_EXPORT
2521 extern void SetDiagHandler(CDiagHandler* handler,
2522                            bool can_delete = true);
2523 
2524 /// Get the currently set diagnostic handler class.
2525 NCBI_XNCBI_EXPORT
2526 extern CDiagHandler* GetDiagHandler(bool take_ownership = false,
2527                                     bool* current_ownership = 0);
2528 
2529 /// Set the diagnostic handler using the specified diagnostic handler
2530 /// and cleanup functions.
2531 NCBI_XNCBI_EXPORT
2532 extern void SetDiagHandler(FDiagHandler func,
2533                            void*        data,
2534                            FDiagCleanup cleanup);
2535 
2536 /// Check if diagnostic handler is set.
2537 ///
2538 /// @return
2539 ///   Return TRUE if user has ever set (or unset) diag. handler.
2540 NCBI_XNCBI_EXPORT
2541 extern bool IsSetDiagHandler(void);
2542 
2543 
2544 /// Ask diagnostic handler to reopen log files if necessary.
2545 NCBI_XNCBI_EXPORT
2546 extern void DiagHandler_Reopen(void);
2547 
2548 
2549 /////////////////////////////////////////////////////////////////////////////
2550 //
2551 // Diagnostic Filter Functionality
2552 //
2553 
2554 /// Diag severity types to put the filter on
2555 ///
2556 /// @sa SetDiagFilter
2557 enum EDiagFilter {
2558     eDiagFilter_Trace,  ///< for TRACEs only
2559     eDiagFilter_Post,   ///< for all non-TRACE, non-FATAL
2560     eDiagFilter_All     ///< for all non-FATAL
2561 };
2562 
2563 
2564 /// Set diagnostic filter
2565 ///
2566 /// Diagnostic filter acts as a second level filtering mechanism
2567 /// (the primary established by global error post level)
2568 /// @param what
2569 ///    Filter is set for
2570 /// @param filter_str
2571 ///    Filter string
2572 /// @sa SetDiagPostLevel
2573 NCBI_XNCBI_EXPORT
2574 extern void SetDiagFilter(EDiagFilter what, const char* filter_str);
2575 
2576 /// Get current diagnostic filter
2577 ///
2578 /// @param what
2579 ///    Filter is set for, only eDiagFilter_Trace and eDiagFilter_Post values are allowed,
2580 ///    otherwise the function returns empty string.
2581 /// @sa SetDiagFilter
2582 NCBI_XNCBI_EXPORT
2583 extern string GetDiagFilter(EDiagFilter what);
2584 
2585 /// Append diagnostic filter
2586 ///
2587 /// @param what
2588 ///    Filter is set for
2589 /// @param filter_str
2590 ///    Filter string
2591 /// @sa SetDiagFilter
2592 NCBI_XNCBI_EXPORT
2593 extern void AppendDiagFilter(EDiagFilter what, const char* filter_str);
2594 
2595 
2596 /////////////////////////////////////////////////////////////////////////////
2597 ///
2598 /// CStreamDiagHandler_Base --
2599 ///
2600 /// Base class for stream and file based handlers
2601 
2602 class NCBI_XNCBI_EXPORT CStreamDiagHandler_Base : public CDiagHandler
2603 {
2604 public:
2605     CStreamDiagHandler_Base(void);
2606 
2607     virtual string GetLogName(void);
GetStream(void)2608     virtual CNcbiOstream* GetStream(void) { return 0; }
2609 
2610 protected:
2611     void SetLogName(const string& log_name);
2612 
2613 private:
2614     char m_LogName[2048];
2615 };
2616 
2617 
2618 /////////////////////////////////////////////////////////////////////////////
2619 ///
2620 /// CStreamDiagHandler --
2621 ///
2622 /// Specialization of "CDiagHandler" for the stream-based diagnostics.
2623 
2624 class NCBI_XNCBI_EXPORT CStreamDiagHandler : public CStreamDiagHandler_Base
2625 {
2626 public:
2627     /// Constructor.
2628     ///
2629     /// This does *not* own the stream; users will need to clean it up
2630     /// themselves if appropriate.
2631     /// @param os
2632     ///   Output stream.
2633     /// @param quick_flush
2634     ///   Do stream flush after every message.
2635     CStreamDiagHandler(CNcbiOstream* os,
2636                        bool          quick_flush = true,
2637                        const string& stream_name = "");
2638 
2639     /// Post message to the handler.
2640     virtual void Post(const SDiagMessage& mess);
GetStream(void)2641     virtual CNcbiOstream* GetStream(void) { return m_Stream; }
2642 
2643 protected:
2644     CNcbiOstream* m_Stream;         ///< Diagnostic stream
2645 
2646 private:
2647     bool          m_QuickFlush;     ///< Quick flush of stream flag
2648 };
2649 
2650 
2651 class CDiagFileHandleHolder;
2652 
2653 /////////////////////////////////////////////////////////////////////////////
2654 ///
2655 /// CFileHandleDiagHandler --
2656 ///
2657 /// Specialization of "CDiagHandler" for the file-handle based diagnostics.
2658 /// Writes messages using system write rather than stream to make the
2659 /// operation really atomic. Re-opens file periodically to make rotation
2660 /// possible.
2661 
2662 class NCBI_XNCBI_EXPORT CFileHandleDiagHandler : public CStreamDiagHandler_Base
2663 {
2664 public:
2665     typedef CStreamDiagHandler_Base TParent;
2666 
2667     /// Constructor.
2668     ///
2669     /// Open file handle.
2670     /// themselves if appropriate.
2671     /// @param fname
2672     ///   Output file name.
2673     CFileHandleDiagHandler(const string& fname);
2674     /// Close file handle
2675     ~CFileHandleDiagHandler(void);
2676 
2677     /// Post message to the handler.
2678     virtual void Post(const SDiagMessage& mess);
2679 
2680     virtual bool AllowAsyncWrite(const SDiagMessage& msg) const;
2681     virtual string ComposeMessage(const SDiagMessage& msg,
2682                                   EDiagFileType*      file_type) const;
2683     virtual void WriteMessage(const char*   buf,
2684                               size_t        len,
2685                               EDiagFileType file_type);
2686 
Valid(void)2687     bool Valid(void)
2688     {
2689         return m_Handle  ||  m_LowDiskSpace;
2690     }
2691 
2692     // Reopen file to enable log rotation.
2693     virtual void Reopen(TReopenFlags flags);
2694 
2695 protected:
2696     virtual void SetLogName(const string& log_name);
2697 
2698 private:
2699     bool        m_LowDiskSpace;
2700     CDiagFileHandleHolder* m_Handle;
2701     CSpinLock*  m_HandleLock;
2702     CStopWatch* m_ReopenTimer;
2703 
2704     /// Save messages if the handle is unavailable
2705     typedef deque<SDiagMessage> TMessages;
2706     unique_ptr<TMessages> m_Messages;
2707 };
2708 
2709 
2710 /////////////////////////////////////////////////////////////////////////////
2711 ///
2712 /// CFileDiagHandler --
2713 ///
2714 /// Specialization of "CDiagHandler" for the file-based diagnostics.
2715 /// Splits output into three files: .err (severity higher than the
2716 /// threshold), .trace (severity below the threshold) and .log
2717 /// (application access log). Re-opens the files periodically
2718 /// to allow safe log rotation.
2719 
2720 class NCBI_XNCBI_EXPORT CFileDiagHandler : public CStreamDiagHandler_Base
2721 {
2722 public:
2723     typedef CStreamDiagHandler_Base TParent;
2724 
2725     /// Constructor. initializes log file(s) with the arguments.
2726     /// @sa SetLogFile
2727     CFileDiagHandler(void);
2728     ~CFileDiagHandler(void);
2729 
2730     /// Post message to the handler. Info and Trace messages are sent
2731     /// to file_name.trace file, all others go to file_name.err file.
2732     /// Application access messages go to file_name.log file.
2733     virtual void Post(const SDiagMessage& mess);
2734 
2735     virtual bool AllowAsyncWrite(const SDiagMessage& msg) const;
2736     virtual string ComposeMessage(const SDiagMessage& msg,
2737                                   EDiagFileType*      file_type) const;
2738     virtual void WriteMessage(const char*   buf,
2739                               size_t        len,
2740                               EDiagFileType file_type);
2741 
2742     /// Set new log file.
2743     ///
2744     /// @param file_name
2745     ///   File name. If file_type is eDiagFile_All, the output will be written
2746     ///   to file_name.(err|log|trace). Otherwise the filename is used as-is.
2747     ///   Special filenames are:
2748     ///     ""          - disable diag messages;
2749     ///     "-"         - print to stderr
2750     ///     "/dev/null" - never add .(err|log|trace) to the name.
2751     /// @param file_type
2752     ///   Type of log file to set - error, trace or application log.
2753     /// @param quick_flush
2754     ///   Do stream flush after every message.
2755     bool SetLogFile(const string& file_name,
2756                     EDiagFileType file_type,
2757                     bool          quick_flush);
2758 
2759     /// Get current log file name. If file_type is eDiagFile_All, always
2760     /// returns empty string.
2761     string GetLogFile(EDiagFileType file_type) const;
2762 
2763     /// Get current log stream. Return NULL if the selected destination
2764     /// is not a stream.
2765     CNcbiOstream* GetLogStream(EDiagFileType file_type);
2766 
2767     // Reopen all files to enable log rotation.
2768     virtual void Reopen(TReopenFlags flags);
2769 
2770     // Set the selected sub-handler directly with the given ownership.
2771     void SetSubHandler(CStreamDiagHandler_Base* handler,
2772                        EDiagFileType            file_type,
2773                        bool                     own);
2774 
2775     /// Change ownership for the given handler if it's currently installed.
2776     void SetOwnership(CStreamDiagHandler_Base* handler, bool own);
2777 
2778 protected:
2779     virtual void SetLogName(const string& log_name);
2780 
2781 private:
2782     // Get file type for the message.
2783     EDiagFileType x_GetDiagFileType(const SDiagMessage& msg) const;
2784     // Get sub-handler for the given file type.
2785     CStreamDiagHandler_Base* x_GetHandler(EDiagFileType file_type) const;
2786 
2787     // Check if the object is owned and if it's used as more than one handler,
2788     // update ownership or delete the handler if necessary.
2789     void x_ResetHandler(CStreamDiagHandler_Base** ptr, bool* owned);
2790     // Set the selected member to the handler, make sure only one
2791     // ownership flag is set for the handler.
2792     void x_SetHandler(CStreamDiagHandler_Base** member,
2793                       bool*                     own_member,
2794                       CStreamDiagHandler_Base*  handler,
2795                       bool                      own);
2796 
2797     CStreamDiagHandler_Base* m_Err;
2798     bool                     m_OwnErr;
2799     CStreamDiagHandler_Base* m_Log;
2800     bool                     m_OwnLog;
2801     CStreamDiagHandler_Base* m_Trace;
2802     bool                     m_OwnTrace;
2803     CStreamDiagHandler_Base* m_Perf;
2804     bool                     m_OwnPerf;
2805     CStopWatch*              m_ReopenTimer;
2806 };
2807 
2808 
2809 //////////////////////////////////////////////////////////////////////////
2810 /// CAsyncDiagHandler --
2811 ///
2812 /// Special handler that offloads physical printing of log messages to a
2813 /// separate thread. This handler should be installed into diagnostics
2814 /// only when it is completely initialized, i.e. no earlier than
2815 /// CNcbiApplication::Run() is called. Also it shouldn't be installed
2816 /// using standard SetDiagHandler() function, you have to use
2817 /// InstallToDiag() method of this handler. And don't forget to call
2818 /// RemoveFromDiag() before your application is finished.
2819 
2820 class CAsyncDiagThread;
2821 
2822 class NCBI_XNCBI_EXPORT CAsyncDiagHandler : public CDiagHandler
2823 {
2824 public:
2825     CAsyncDiagHandler(void);
2826     virtual ~CAsyncDiagHandler(void);
2827 
2828     /// Install this DiagHandler into diagnostics.
2829     /// Method should be called only when diagnostics is completely
2830     /// initialized, i.e. no earlier than CNcbiApplication::Run() is called.
2831     /// Method can throw CThreadException if dedicated thread failed
2832     /// to start.
2833     /// @deprecated Use regular diganostics instead.
2834     NCBI_DEPRECATED
2835     void InstallToDiag(void);
2836     /// Remove this DiagHandler from diagnostics.
2837     /// This method must be called if InstallToDiag was called. Object cannot
2838     /// be destroyed if InstallToDiag was called and RemoveFromDiag wasn't
2839     /// called. If InstallToDiag wasn't called then this method does nothing
2840     /// and is safe to be executed.
2841     void RemoveFromDiag(void);
2842     /// Set custom suffix to use on all threads in the server's pool.
2843     /// Value can be set only before call to InstallToDiag(), any change
2844     /// of the value after call to InstallToDiag() will be ignored.
2845     void SetCustomThreadSuffix(const string& suffix);
2846 
2847     /// Implementation of CDiagHandler
2848     virtual void Post(const SDiagMessage& mess);
2849     virtual string GetLogName(void);
2850     virtual void Reopen(TReopenFlags flags);
2851 
2852 private:
2853     /// Thread handling all physical printing of log messages
2854     CAsyncDiagThread* m_AsyncThread;
2855     string m_ThreadSuffix;
2856 };
2857 
2858 
2859 /// Output diagnostics using both old and new style handlers.
2860 NCBI_DEPRECATED
2861 NCBI_XNCBI_EXPORT extern void SetDoubleDiagHandler(void); ///< @deprecated
2862 
2863 
2864 /// Set diagnostic stream.
2865 ///
2866 /// Error diagnostics are written to output stream "os".
2867 /// This uses the SetDiagHandler() functionality.
2868 NCBI_XNCBI_EXPORT
2869 extern void SetDiagStream
2870 (CNcbiOstream* os,
2871  bool          quick_flush  = true, ///< Do stream flush after every message
2872  FDiagCleanup  cleanup      = 0,    ///< Call "cleanup(cleanup_data)" if diag.
2873  void*         cleanup_data = 0,    ///< Stream is changed (see SetDiagHandler)
2874  const string& stream_name  = ""    ///< Stream name (e.g. STDERR, file.log)
2875  );
2876 
2877 // Return TRUE if "os" is the current diag. stream.
2878 NCBI_XNCBI_EXPORT
2879 extern bool IsDiagStream(const CNcbiOstream* os);
2880 
2881 /// Get current diagnostic stream (if it was set by SetDiagStream) or NULL.
2882 NCBI_XNCBI_EXPORT
2883 extern CNcbiOstream* GetDiagStream(void);
2884 
2885 /// Split log files flag. If set, the output is sent to different
2886 /// log files depending on the severity level.
2887 NCBI_XNCBI_EXPORT extern void SetSplitLogFile(bool value = true);
2888 /// Get split log files flag.
2889 NCBI_XNCBI_EXPORT extern bool GetSplitLogFile(void);
2890 
2891 /// Set log files.
2892 /// Send output to file_name or to file_name.(err|log|trace) depending
2893 /// on the split log file flag and file_type. If a single file type
2894 /// is selected, other types remain the same or are switched to
2895 /// stderr if their files have not been assigned yet.
2896 /// If split log flag is off, any file type except eDiagFile_All
2897 /// will be ignored.
2898 /// If the file_name contains one of the extensions .log, .err or .trace
2899 /// and the file type is eDiagFile_All, the extension will be removed
2900 /// before adding the new one.
2901 /// Return true on success, false if the file could not be open.
2902 NCBI_XNCBI_EXPORT
2903 extern bool SetLogFile(const string& file_name,
2904                        EDiagFileType file_type = eDiagFile_All,
2905                        bool          quick_flush = true);
2906 
2907 /// Get log file name for the given log type. Return empty string for
2908 /// eDiagFile_All or if the log file handler is not installed.
2909 NCBI_XNCBI_EXPORT
2910 extern string GetLogFile(EDiagFileType file_type);
2911 
2912 /// Get log file name or diag handler name.
2913 NCBI_XNCBI_EXPORT
2914 extern string GetLogFile(void);
2915 
2916 
2917 /// Use RW-lock for synchronization rather than mutex.
2918 /// NOTE:
2919 /// 1. The function should never be called when there are
2920 /// several threads running. Otherwise the result may
2921 /// be unpredictable. Also, do not call it from any diagnostic
2922 /// framework functions. E.g., it can not be called from
2923 /// CSomeDiagHandler::Post(). The best place to switch
2924 /// is in the very beginning of main().
2925 /// 2. In many cases switching to RW-lock will not improve
2926 /// the performance. E.g. any stream-based diag handlers including
2927 /// stderr will have to lock a mutex before writing a message anyway.
2928 /// Significant improvement may be seen only when using file handle
2929 /// based handlers which do atomic writes without additional locks.
2930 /// 3. If a custom diag handler is installed, it must take care
2931 /// about synchronization in Post() method. The framework only sets
2932 /// read lock before Post(), so it may be called from multiple
2933 /// threads at the same time.
2934 /// If in doubt, do not turn this on.
2935 /// The returned value is true on success, false if the switching
2936 /// fails for any reason.
2937 NCBI_XNCBI_EXPORT
2938 extern void g_Diag_Use_RWLock(bool enable = true);
2939 
2940 
2941 /////////////////////////////////////////////////////////////////////////////
2942 ///
2943 /// CDiagFactory --
2944 ///
2945 /// Diagnostic handler factory.
2946 
2947 class NCBI_XNCBI_EXPORT CDiagFactory
2948 {
2949 public:
~CDiagFactory()2950     virtual ~CDiagFactory() { }
2951     /// Factory method interface.
2952     virtual CDiagHandler* New(const string& s) = 0;
2953 };
2954 
2955 
2956 
2957 /////////////////////////////////////////////////////////////////////////////
2958 ///
2959 /// CDiagRestorer --
2960 ///
2961 /// Auxiliary class to limit the duration of changes to diagnostic settings.
2962 
2963 class NCBI_XNCBI_EXPORT CDiagRestorer
2964 {
2965 public:
2966     CDiagRestorer (void); ///< Captures current settings
2967     ~CDiagRestorer(void); ///< Restores captured settings
2968 private:
2969     /// Private new operator.
2970     ///
2971     /// Prohibit dynamic allocation because there's no good reason to allow
2972     /// it, and out-of-order destruction is problematic.
operator new(size_t)2973     void* operator new      (size_t)  { throw runtime_error("forbidden"); }
2974 
2975     /// Private new[] operator.
2976     ///
2977     /// Prohibit dynamic allocation because there's no good reason to allow
2978     /// it, and out-of-order destruction is problematic.
operator new[](size_t)2979     void* operator new[]    (size_t)  { throw runtime_error("forbidden"); }
2980 
2981     /// Private delete operator.
2982     ///
2983     /// Prohibit dynamic deallocation (and allocation) because there's no
2984     /// good reason to allow it, and out-of-order destruction is problematic.
operator delete(void *)2985     void  operator delete   (void*)   { }
2986 
2987     /// Private delete[] operator.
2988     ///
2989     /// Prohibit dynamic deallocation (and allocation) because there's no
2990     /// good reason to allow it, and out-of-order destruction is problematic.
operator delete[](void *)2991     void  operator delete[] (void*)   { }
2992 
2993     string            m_PostPrefix;            ///< Message prefix
2994     list<string>      m_PrefixList;            ///< List of prefixes
2995     TDiagPostFlags    m_PostFlags;             ///< Post flags
2996     EDiagSev          m_PostSeverity;          ///< Post severity
2997     EDiagSevChange    m_PostSeverityChange;    ///< Severity change
2998     bool              m_IgnoreToDie;           ///< Ignore to die on die sev
2999     EDiagSev          m_DieSeverity;           ///< Die level severity
3000     EDiagTrace        m_TraceDefault;          ///< Default trace setting
3001     bool              m_TraceEnabled;          ///< Trace enabled?
3002     CDiagHandler*     m_Handler;               ///< Class handler
3003     bool              m_CanDeleteHandler;      ///< Can handler be deleted?
3004     CDiagErrCodeInfo* m_ErrCodeInfo;           ///< Error code information
3005     bool              m_CanDeleteErrCodeInfo;  ///< Can delete err code info?
3006     bool              m_ApplogSeverityLocked;  ///< Limiting applog post level?
3007 };
3008 
3009 
3010 
3011 /////////////////////////////////////////////////////////////////////////////
3012 ///
3013 /// SDiagErrCodeDescription --
3014 ///
3015 /// Structure used to store the errors code and subcode description.
3016 
3017 struct NCBI_XNCBI_EXPORT SDiagErrCodeDescription {
3018     /// Constructor.
3019     SDiagErrCodeDescription(void);
3020 
3021     /// Destructor.
SDiagErrCodeDescriptionSDiagErrCodeDescription3022     SDiagErrCodeDescription(const string& message,     ///< Message
3023                             const string& explanation, ///< Explanation of msg.
3024                             int           severity = -1
3025                                                        ///< Do not override
3026                                                        ///< if set to -1
3027                            )
3028         : m_Message(message),
3029           m_Explanation(explanation),
3030           m_Severity(severity)
3031     {
3032         return;
3033     }
3034 
3035 public:
3036     string m_Message;     ///< Error message (short)
3037     string m_Explanation; ///< Error message (with detailed explanation)
3038     int    m_Severity;
3039                           ///< Message severity (if less that 0, then use
3040                           ///< current diagnostic severity level)
3041 };
3042 
3043 
3044 
3045 /////////////////////////////////////////////////////////////////////////////
3046 ///
3047 /// CDiagErrCodeInfo --
3048 ///
3049 /// Stores mapping of error codes and their descriptions.
3050 
3051 class NCBI_XNCBI_EXPORT CDiagErrCodeInfo
3052 {
3053 public:
3054     /// Constructor.
3055     CDiagErrCodeInfo(void);
3056 
3057     /// Constructor -- can throw runtime_error.
3058     CDiagErrCodeInfo(const string& file_name);
3059 
3060     /// Constructor -- can throw runtime_error.
3061     CDiagErrCodeInfo(CNcbiIstream& is);
3062 
3063     /// Destructor.
3064     ~CDiagErrCodeInfo(void);
3065 
3066     /// Read error description from specified file.
3067     ///
3068     /// Read error descriptions from the specified file,
3069     /// store it in memory.
3070     bool Read(const string& file_name);
3071 
3072     /// Read error description from specified stream.
3073     ///
3074     /// Read error descriptions from the specified stream,
3075     /// store it in memory.
3076     bool Read(CNcbiIstream& is);
3077 
3078     /// Delete all stored error descriptions from memory.
3079     void Clear(void);
3080 
3081     /// Get description for specified error code.
3082     ///
3083     /// Get description message for the error by its code.
3084     /// @return
3085     ///   TRUE if error description exists for this code;
3086     ///   return FALSE otherwise.
3087     bool GetDescription(const ErrCode&           err_code,
3088                         SDiagErrCodeDescription* description) const;
3089 
3090     /// Set error description for specified error code.
3091     ///
3092     /// If description for this code already exist, then it
3093     /// will be overwritten.
3094     void SetDescription(const ErrCode&                 err_code,
3095                         const SDiagErrCodeDescription& description);
3096 
3097     /// Check if error description exists.
3098     ///
3099     ///  Return TRUE if description for specified error code exists,
3100     /// otherwise return FALSE.
3101     bool HaveDescription(const ErrCode& err_code) const;
3102 
3103 private:
3104 
3105     /// Define map for error messages.
3106     typedef map<ErrCode, SDiagErrCodeDescription> TInfo;
3107 
3108     /// Map storing error codes and descriptions.
3109     TInfo m_Info;
3110 };
3111 
3112 
3113 
3114 /// Diagnostic message file.
3115 #define DIAG_MESSAGE_FILE "MessageFile"
3116 
3117 /// Set handler for processing error codes.
3118 ///
3119 /// By default this handler is unset.
3120 /// NcbiApplication can init itself only if registry key DIAG_MESSAGE_FILE
3121 /// section DEBUG) is specified. The value of this key should be a name
3122 /// of the file with the error codes explanations.
3123 NCBI_XNCBI_EXPORT
3124 extern void SetDiagErrCodeInfo(CDiagErrCodeInfo* info,
3125                                bool              can_delete = true);
3126 
3127 /// Indicates whether an error-code processing handler has been set.
3128 NCBI_XNCBI_EXPORT
3129 extern bool IsSetDiagErrCodeInfo();
3130 
3131 /// Get handler for processing error codes.
3132 NCBI_XNCBI_EXPORT
3133 extern CDiagErrCodeInfo* GetDiagErrCodeInfo(bool take_ownership = false);
3134 
3135 
3136 /* @} */
3137 
3138 
3139 ///////////////////////////////////////////////////////
3140 // All inline function implementations and internal data
3141 // types, etc. are in this file
3142 
3143 #include <corelib/ncbidiag.inl>
3144 
3145 
3146 END_NCBI_SCOPE
3147 
3148 
3149 #endif  /* CORELIB___NCBIDIAG__HPP */
3150