1#if defined(CORELIB___NCBIDIAG__HPP) && !defined(CORELIB___NCBIDIAG__INL) 2#define CORELIB___NCBIDIAG__INL 3 4/* $Id: ncbidiag.inl 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 * File Description: 32 * NCBI C++ diagnostic API 33 * 34 */ 35 36 37///////////////////////////////////////////////////////////////////////////// 38// WARNING -- all the beneath is for INTERNAL "ncbidiag" use only, 39// and any classes, typedefs and even "extern" functions and 40// variables declared in this file should not be used anywhere 41// but inside "ncbidiag.inl" and/or "ncbidiag.cpp"!!! 42///////////////////////////////////////////////////////////////////////////// 43 44 45////////////////////////////////////////////////////////////////// 46// CDiagBuffer 47// (can be accessed only by "CNcbiDiag" and "CDiagRestorer" 48// and created only by GetDiagBuffer()) 49// 50 51 52class CDiagBuffer 53{ 54 CDiagBuffer(const CDiagBuffer&); 55 CDiagBuffer& operator= (const CDiagBuffer&); 56 57 friend class CDiagContextThreadData; 58 friend class CDiagContext_Extra; 59 60 // Flags 61 friend bool IsSetDiagPostFlag(EDiagPostFlag flag, TDiagPostFlags flags); 62 NCBI_XNCBI_EXPORT 63 friend TDiagPostFlags SetDiagPostAllFlags(TDiagPostFlags flags); 64 NCBI_XNCBI_EXPORT friend void SetDiagPostFlag(EDiagPostFlag flag); 65 NCBI_XNCBI_EXPORT friend void UnsetDiagPostFlag(EDiagPostFlag flag); 66 NCBI_XNCBI_EXPORT 67 friend TDiagPostFlags SetDiagTraceAllFlags(TDiagPostFlags flags); 68 NCBI_XNCBI_EXPORT friend void SetDiagTraceFlag(EDiagPostFlag flag); 69 NCBI_XNCBI_EXPORT friend void UnsetDiagTraceFlag(EDiagPostFlag flag); 70 NCBI_XNCBI_EXPORT friend void SetDiagPostPrefix(const char* prefix); 71 NCBI_XNCBI_EXPORT friend void PushDiagPostPrefix(const char* prefix); 72 NCBI_XNCBI_EXPORT friend void PopDiagPostPrefix(void); 73 74 // 75 friend class CNcbiDiag; 76 friend const CNcbiDiag& Reset(const CNcbiDiag& diag); 77 friend const CNcbiDiag& Endm(const CNcbiDiag& diag); 78 79 // Severity 80 NCBI_XNCBI_EXPORT 81 friend EDiagSev SetDiagPostLevel(EDiagSev post_sev); 82 NCBI_XNCBI_EXPORT 83 friend EDiagSev GetDiagPostLevel(void); 84 NCBI_XNCBI_EXPORT 85 friend bool IsVisibleDiagPostLevel(EDiagSev sev); 86 NCBI_XNCBI_EXPORT 87 friend void SetDiagFixedPostLevel(EDiagSev post_sev); 88 NCBI_XNCBI_EXPORT 89 friend bool DisableDiagPostLevelChange(bool disable_change); 90 NCBI_XNCBI_EXPORT 91 friend EDiagSev SetDiagDieLevel(EDiagSev die_sev); 92 NCBI_XNCBI_EXPORT 93 friend EDiagSev GetDiagDieLevel(void); 94 NCBI_XNCBI_EXPORT 95 friend bool IgnoreDiagDieLevel(bool ignore); 96 97 // Others 98 NCBI_XNCBI_EXPORT 99 friend void SetDiagTrace(EDiagTrace how, EDiagTrace dflt); 100 NCBI_XNCBI_EXPORT 101 friend bool GetDiagTrace(void); 102 NCBI_XNCBI_EXPORT friend bool IsDiagStream(const CNcbiOstream* os); 103 104 // Handler 105 NCBI_XNCBI_EXPORT friend void 106 SetDiagHandler(CDiagHandler* handler, bool can_delete); 107 NCBI_XNCBI_EXPORT friend CDiagHandler* GetDiagHandler(bool take_ownership, 108 bool* current_ownership); 109 NCBI_XNCBI_EXPORT friend bool IsSetDiagHandler(void); 110 111 // Error code information 112 NCBI_XNCBI_EXPORT 113 friend void SetDiagErrCodeInfo(CDiagErrCodeInfo* info, bool can_delete); 114 NCBI_XNCBI_EXPORT 115 friend CDiagErrCodeInfo* GetDiagErrCodeInfo(bool take_ownership); 116 NCBI_XNCBI_EXPORT 117 friend bool IsSetDiagErrCodeInfo(void); 118 119private: 120 friend class CDiagRestorer; 121 friend class CDiagContext; 122 friend class CDiagCollectGuard; 123 124 const CNcbiDiag* m_Diag; // present user 125 CNcbiOstrstream* m_Stream; // storage for the diagnostic message 126 IOS_BASE::fmtflags m_InitialStreamFlags; 127 bool m_InUse; // Protection against nested posts 128 129 // user-specified string to add to each posted message 130 // (can be constructed from "m_PrefixList" after push/pop operations) 131 string m_PostPrefix; 132 133 // list of prefix strings to compose the "m_PostPrefix" from 134 typedef list<string> TPrefixList; 135 TPrefixList m_PrefixList; 136 137 CDiagBuffer(void); 138 139 //### This is a temporary workaround to allow call the destructor of 140 //### static instance of "CDiagBuffer" defined in GetDiagBuffer() 141public: 142 ~CDiagBuffer(void); 143private: 144 //### 145 146 // formatted output 147 template<class X> void Put(const CNcbiDiag& diag, const X& x) { 148 if ( SetDiag(diag) ) 149 (*m_Stream) << x; 150 } 151 152 NCBI_XNCBI_EXPORT 153 void Flush (void); 154 void PrintMessage(SDiagMessage& mess, const CNcbiDiag& diag); 155 void Reset (const CNcbiDiag& diag); // reset content of the diag.message 156 void EndMess(const CNcbiDiag& diag); // output current diag. message 157 NCBI_XNCBI_EXPORT 158 bool SetDiag(const CNcbiDiag& diag); 159 160 // flush & detach the current user 161 void Detach(const CNcbiDiag* diag); 162 163 // compose the post prefix using "m_PrefixList" 164 void UpdatePrefix(void); 165 166 // the bitwise OR combination of "EDiagPostFlag" 167 // Hidden inside the function to adjust default flags depending on 168 // registry/environment. 169 // inline version 170 static TDiagPostFlags& sx_GetPostFlags(void); 171 // non-inline version 172 NCBI_XNCBI_EXPORT 173 static TDiagPostFlags& s_GetPostFlags(void); 174 // extra flags ORed in for traces 175 static TDiagPostFlags sm_TraceFlags; 176 177 // static members 178 static EDiagSev sm_PostSeverity; 179 static EDiagSevChange sm_PostSeverityChange; 180 // severity level changing status 181 static bool sm_IgnoreToDie; 182 static EDiagSev sm_DieSeverity; 183 static EDiagTrace sm_TraceDefault; // default state of tracing 184 static bool sm_TraceEnabled; // current state of tracing 185 // (enable/disable) 186 187 static bool GetTraceEnabled(void); // dont access sm_TraceEnabled 188 // directly 189 static bool GetTraceEnabledFirstTime(void); 190 static bool GetSeverityChangeEnabledFirstTime(void); 191 // Anything not disabled but also not printable is collectable. 192 static bool SeverityDisabled(EDiagSev sev); 193 static bool SeverityPrintable(EDiagSev sev); 194 195 // call the current diagnostics handler directly 196 static void DiagHandler(SDiagMessage& mess); 197 198 // Symbolic name for the severity levels(used by CNcbiDiag::SeverityName) 199 NCBI_XNCBI_EXPORT 200 static const char* sm_SeverityName[eDiag_Trace+1]; 201 202 // Application-wide diagnostic handler 203 static CDiagHandler* sm_Handler; 204 static bool sm_CanDeleteHandler; 205 206 // Error codes info 207 static CDiagErrCodeInfo* sm_ErrCodeInfo; 208 static bool sm_CanDeleteErrCodeInfo; 209 210 friend NCBI_XNCBI_EXPORT 211 CDiagContext_Extra g_PostPerf(int status, 212 double timespan, 213 SDiagMessage::TExtraArgs& args); 214}; 215 216extern CDiagBuffer& GetDiagBuffer(void); 217 218 219/////////////////////////////////////////////////////// 220// CDiagCompileInfo 221 222inline const char* CDiagCompileInfo::GetFile (void) const 223{ 224 return m_File; 225} 226 227inline const char* CDiagCompileInfo::GetModule(void) const 228{ 229 return m_Module; 230} 231 232inline int CDiagCompileInfo::GetLine(void) const 233{ 234 return m_Line; 235} 236 237inline const string& CDiagCompileInfo::GetClass(void) const 238{ 239 if (!m_ClassSet && !m_Parsed) { 240 ParseCurrFunctName(); 241 } 242 return m_ClassName; 243} 244 245inline const string& CDiagCompileInfo::GetFunction(void) const 246{ 247 if (!m_Parsed) { 248 ParseCurrFunctName(); 249 } 250 return m_FunctName; 251} 252 253 254/////////////////////////////////////////////////////// 255// CNcbiDiag:: 256 257template<class X> 258inline 259const CNcbiDiag& CNcbiDiag::Put(const volatile void*, const X& x) const 260{ 261 m_Buffer.Put(*this, x); 262 return *this; 263} 264 265 266inline const CNcbiDiag& CNcbiDiag::operator<< (FIosbaseManip manip) const 267{ 268 m_Buffer.Put(*this, manip); 269 return *this; 270} 271 272inline const CNcbiDiag& CNcbiDiag::operator<< (FIosManip manip) const 273{ 274 m_Buffer.Put(*this, manip); 275 return *this; 276} 277 278 279inline const CNcbiDiag& CNcbiDiag::SetLine(size_t line) const { 280 m_CompileInfo.SetLine((int)line); 281 return *this; 282} 283 284inline const CNcbiDiag& CNcbiDiag::SetErrorCode(int code, int subcode) const { 285 m_ErrCode = code; 286 m_ErrSubCode = subcode; 287 return *this; 288} 289 290inline EDiagSev CNcbiDiag::GetSeverity(void) const { 291 return m_Severity; 292} 293 294inline const char* CNcbiDiag::GetModule(void) const 295{ 296 return m_CompileInfo.GetModule(); 297} 298 299inline const char* CNcbiDiag::GetFile(void) const 300{ 301 return m_CompileInfo.GetFile(); 302} 303 304inline const char* CNcbiDiag::GetClass(void) const 305{ 306 return m_CompileInfo.GetClass().c_str(); 307} 308 309inline const char* CNcbiDiag::GetFunction(void) const 310{ 311 return m_CompileInfo.GetFunction().c_str(); 312} 313 314inline size_t CNcbiDiag::GetLine(void) const { 315 return m_CompileInfo.GetLine(); 316} 317 318inline int CNcbiDiag::GetErrorCode(void) const { 319 return m_ErrCode; 320} 321 322inline int CNcbiDiag::GetErrorSubCode(void) const { 323 return m_ErrSubCode; 324} 325 326inline TDiagPostFlags CNcbiDiag::GetPostFlags(void) const { 327 return (m_PostFlags & eDPF_Default) ? 328 (m_PostFlags | CDiagBuffer::s_GetPostFlags()) & ~eDPF_Default : 329 m_PostFlags; 330} 331 332inline void CNcbiDiag::SetAllPostFlags(TDiagPostFlags flags) const { 333 m_PostFlags = flags; 334} 335 336inline TDiagPostFlags CNcbiDiag::SetPostFlags(TDiagPostFlags flags) const { 337 return (m_PostFlags = (GetPostFlags() | flags)); 338} 339 340inline TDiagPostFlags CNcbiDiag::ResetPostFlags(TDiagPostFlags flags) const { 341 return (m_PostFlags = (GetPostFlags() & ~flags)); 342} 343 344inline 345const char* CNcbiDiag::SeverityName(EDiagSev sev) { 346 return CDiagBuffer::sm_SeverityName[sev]; 347} 348 349 350/////////////////////////////////////////////////////// 351// ErrCode - class for manipulator ErrCode 352 353inline 354void CNcbiDiag::x_EndMess(void) const 355{ 356 m_Buffer.EndMess(*this); 357} 358 359inline 360const CNcbiDiag& CNcbiDiag::Put(const ErrCode*, const ErrCode& err_code) const 361{ 362 x_EndMess(); 363 return SetErrorCode(err_code.m_Code, err_code.m_SubCode); 364} 365 366inline 367bool operator< (const ErrCode& ec1, const ErrCode& ec2) 368{ 369 return (ec1.m_Code == ec2.m_Code) 370 ? (ec1.m_SubCode < ec2.m_SubCode) 371 : (ec1.m_Code < ec2.m_Code); 372} 373 374 375/////////////////////////////////////////////////////// 376// Other CNcbiDiag:: manipulators 377 378inline 379const CNcbiDiag& CNcbiDiag::Put(const Severity*, 380 const Severity& severity) const 381{ 382 x_EndMess(); 383 m_Severity = severity.m_Level; 384 return *this; 385} 386 387inline 388const CNcbiDiag& CNcbiDiag::Put(const NCBI_NS_NCBI::SetPostFlags*, 389 const NCBI_NS_NCBI::SetPostFlags& flags) const 390{ 391 x_EndMess(); 392 SetPostFlags(flags.m_Flags); 393 return *this; 394} 395 396inline 397const CNcbiDiag& Reset(const CNcbiDiag& diag) { 398 diag.m_Buffer.Reset(diag); 399 diag.ResetIsMessageFlag(); 400 diag.ResetIsConsoleFlag(); 401 diag.SetErrorCode(0, 0); 402 return diag; 403} 404 405inline 406const CNcbiDiag& Endm(const CNcbiDiag& diag) { 407 if ( !diag.m_Buffer.m_Diag 408 && (diag.GetErrorCode() || diag.GetErrorSubCode()) ) { 409 diag.m_Buffer.SetDiag(diag); 410 } 411 diag.m_Buffer.EndMess(diag); 412 return diag; 413} 414 415// No-return version of Endm(), used in ERR_FATAL* set of macros 416NCBI_NORETURN NCBI_XNCBI_EXPORT 417void EndmFatal(const CNcbiDiag& diag); 418 419inline 420const CNcbiDiag& Info(const CNcbiDiag& diag) { 421 diag.x_EndMess(); 422 diag.m_Severity = eDiag_Info; 423 return diag; 424} 425inline 426const CNcbiDiag& Warning(const CNcbiDiag& diag) { 427 diag.x_EndMess(); 428 diag.m_Severity = eDiag_Warning; 429 return diag; 430} 431inline 432const CNcbiDiag& Error(const CNcbiDiag& diag) { 433 diag.x_EndMess(); 434 diag.m_Severity = eDiag_Error; 435 return diag; 436} 437inline 438const CNcbiDiag& Critical(const CNcbiDiag& diag) { 439 diag.x_EndMess(); 440 diag.m_Severity = eDiag_Critical; 441 return diag; 442} 443inline 444const CNcbiDiag& Fatal(const CNcbiDiag& diag) { 445 diag.x_EndMess(); 446 diag.m_Severity = eDiag_Fatal; 447 return diag; 448} 449inline 450const CNcbiDiag& Trace(const CNcbiDiag& diag) { 451 diag.x_EndMess(); 452 diag.m_Severity = eDiag_Trace; 453 return diag; 454} 455inline 456const CNcbiDiag& Message(const CNcbiDiag& diag) { 457 diag.x_EndMess(); 458 diag.m_PostFlags |= eDPF_IsNote; 459 return diag; 460} 461inline 462const CNcbiDiag& Note(const CNcbiDiag& diag) { 463 diag.x_EndMess(); 464 diag.m_PostFlags |= eDPF_IsNote; 465 return diag; 466} 467inline 468const CNcbiDiag& Console(const CNcbiDiag& diag) { 469 diag.x_EndMess(); 470 diag.m_PostFlags |= eDPF_IsConsole; 471 return diag; 472} 473 474inline 475const CNcbiDiag& StackTrace (const CNcbiDiag& diag) { 476 CStackTrace stk; 477 diag.Put(NULL,stk); 478 return diag; 479} 480 481 482 483/////////////////////////////////////////////////////// 484// CDiagBuffer:: 485 486inline 487void CDiagBuffer::Reset(const CNcbiDiag& diag) { 488 if (&diag == m_Diag) { 489 m_Stream->rdbuf()->PUBSEEKOFF(0, IOS_BASE::beg, IOS_BASE::out); 490 } 491} 492 493inline 494void CDiagBuffer::EndMess(const CNcbiDiag& diag) { 495 if (&diag == m_Diag) { 496 // Flush(); 497 Detach(&diag); 498 diag.SetErrorCode(0, 0); 499 } 500} 501 502inline 503void CDiagBuffer::Detach(const CNcbiDiag* diag) { 504 if (diag == m_Diag) { 505 Flush(); 506 m_Diag = 0; 507 } 508} 509 510inline 511bool CDiagBuffer::GetTraceEnabled(void) { 512 return (sm_TraceDefault == eDT_Default) ? 513 GetTraceEnabledFirstTime() : sm_TraceEnabled; 514} 515 516 517/////////////////////////////////////////////////////// 518// EDiagPostFlag:: 519 520inline 521bool IsSetDiagPostFlag(EDiagPostFlag flag, TDiagPostFlags flags) { 522 if (flags & eDPF_Default) 523 flags |= CDiagBuffer::s_GetPostFlags(); 524 return (flags & flag) != 0; 525} 526 527 528/////////////////////////////////////////////////////// 529// CDiagErrCodeInfo:: 530 531 532inline 533CDiagErrCodeInfo::CDiagErrCodeInfo(void) 534{ 535 return; 536} 537 538 539inline 540CDiagErrCodeInfo::CDiagErrCodeInfo(const string& file_name) 541{ 542 if ( !Read(file_name) ) { 543 throw runtime_error 544 ("CDiagErrCodeInfo:: failed to read error descriptions from file " 545 + file_name); 546 } 547} 548 549 550inline 551CDiagErrCodeInfo::CDiagErrCodeInfo(CNcbiIstream& is) 552{ 553 if ( !Read(is) ) { 554 throw runtime_error 555 ("CDiagErrCodeInfo:: failed to read error descriptions"); 556 } 557} 558 559 560inline 561CDiagErrCodeInfo::~CDiagErrCodeInfo(void) 562{ 563 Clear(); 564} 565 566 567inline 568void CDiagErrCodeInfo::Clear(void) 569{ 570 m_Info.clear(); 571} 572 573 574inline 575void CDiagErrCodeInfo::SetDescription 576(const ErrCode& err_code, 577 const SDiagErrCodeDescription& description) 578{ 579 m_Info[err_code] = description; 580} 581 582 583inline 584bool CDiagErrCodeInfo::HaveDescription(const ErrCode& err_code) const 585{ 586 return m_Info.find(err_code) != m_Info.end(); 587} 588 589 590///////////////////////////////////////////////////////////////////////////// 591/// MDiagModuleCpp:: 592 593/*inline 594const CNcbiDiag& operator<< (const CNcbiDiag& diag, 595 const MDiagModuleCpp& module) 596{ 597 if(module.m_Module) 598 diag.SetModule(module.m_Module); 599 return diag; 600 }*/ 601 602 603///////////////////////////////////////////////////////////////////////////// 604/// MDiagModule:: 605 606inline 607MDiagModule::MDiagModule(const char* module) 608 : m_Module(module) 609{ 610} 611 612 613inline 614const CNcbiDiag& operator<< (const CNcbiDiag& diag, const MDiagModule& module) 615{ 616 return diag.SetModule(module.m_Module); 617} 618 619 620 621///////////////////////////////////////////////////////////////////////////// 622/// MDiagClass:: 623 624inline 625MDiagClass::MDiagClass(const char* nclass) 626 : m_Class(nclass) 627{ 628} 629 630 631inline 632const CNcbiDiag& operator<< (const CNcbiDiag& diag, const MDiagClass& nclass) 633{ 634 return diag.SetClass(nclass.m_Class); 635} 636 637 638 639///////////////////////////////////////////////////////////////////////////// 640/// MDiagFunction:: 641 642inline 643MDiagFunction::MDiagFunction(const char* function) 644 : m_Function(function) 645{ 646} 647 648 649inline 650const CNcbiDiag& operator<< (const CNcbiDiag& diag, const MDiagFunction& function) 651{ 652 return diag.SetFunction(function.m_Function); 653} 654 655 656// The function should not be called directly, use performance guard instead. 657// The 'args' list elements will be moved to the CDiagContext_Extra. 658NCBI_XNCBI_EXPORT 659extern CDiagContext_Extra g_PostPerf(int status, 660 double timespan, 661 SDiagMessage::TExtraArgs& args); 662 663#endif /* def CORELIB___NCBIDIAG__HPP && ndef CORELIB___NCBIDIAG__INL */ 664