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