📄 ncbidiag.cpp
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbidiag.cpp,v $ * PRODUCTION Revision 1000.4 2004/06/01 19:08:57 gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.80 * PRODUCTION * =========================================================================== *//* $Id: ncbidiag.cpp,v 1000.4 2004/06/01 19:08:57 gouriano Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: Denis Vakatov * * File Description: * NCBI C++ diagnostic API * */#include <ncbi_pch.hpp>#include <ncbiconf.h>#include <corelib/ncbidiag.hpp>#include <corelib/ncbithr.hpp>#include <corelib/ncbimtx.hpp>#include <corelib/ncbi_safe_static.hpp>#include <corelib/ncbiexpt.hpp>#include <stdlib.h>#include <time.h>#include <stack>#if defined(NCBI_OS_MAC)# include <corelib/ncbi_os_mac.hpp>#endifBEGIN_NCBI_SCOPEDEFINE_STATIC_MUTEX(s_DiagMutex);#if defined(NCBI_POSIX_THREADS) && defined(HAVE_PTHREAD_ATFORK)#include <unistd.h> // for pthread_atfork()extern "C" { static void s_NcbiDiagPreFork(void) { s_DiagMutex.Lock(); } static void s_NcbiDiagPostFork(void) { s_DiagMutex.Unlock(); }}#endif///////////////////////////////////////////////////////// CDiagRecycler::class CDiagRecycler {public: CDiagRecycler(void) {#if defined(NCBI_POSIX_THREADS) && defined(HAVE_PTHREAD_ATFORK) pthread_atfork(s_NcbiDiagPreFork, // before s_NcbiDiagPostFork, // after in parent s_NcbiDiagPostFork); // after in child#endif } ~CDiagRecycler(void) { SetDiagHandler(0, false); SetDiagErrCodeInfo(0, false); }};static CSafeStaticPtr<CDiagRecycler> s_DiagRecycler;///////////////////////////////////////////////////////// CDiagBuffer::#if defined(NDEBUG)EDiagSev CDiagBuffer::sm_PostSeverity = eDiag_Error;#elseEDiagSev CDiagBuffer::sm_PostSeverity = eDiag_Warning;#endif /* else!NDEBUG */EDiagSevChange CDiagBuffer::sm_PostSeverityChange = eDiagSC_Unknown; // to be set on first requestTDiagPostFlags CDiagBuffer::sm_PostFlags = eDPF_Prefix | eDPF_Severity | eDPF_ErrCode | eDPF_ErrSubCode | eDPF_ErrCodeMessage | eDPF_ErrCodeExplanation | eDPF_ErrCodeUseSeverity;TDiagPostFlags CDiagBuffer::sm_TraceFlags = eDPF_Trace;EDiagSev CDiagBuffer::sm_DieSeverity = eDiag_Fatal;EDiagTrace CDiagBuffer::sm_TraceDefault = eDT_Default;bool CDiagBuffer::sm_TraceEnabled; // to be set on first requestconst char* CDiagBuffer::sm_SeverityName[eDiag_Trace+1] = { "Info", "Warning", "Error", "Critical", "Fatal", "Trace" };// Use s_DefaultHandler only for purposes of comparison, as installing// another handler will normally delete it.CDiagHandler* s_DefaultHandler = new CStreamDiagHandler(&NcbiCerr);CDiagHandler* CDiagBuffer::sm_Handler = s_DefaultHandler;bool CDiagBuffer::sm_CanDeleteHandler = true;CDiagErrCodeInfo* CDiagBuffer::sm_ErrCodeInfo = 0;bool CDiagBuffer::sm_CanDeleteErrCodeInfo = false;CDiagBuffer::CDiagBuffer(void) : m_Stream(new CNcbiOstrstream){ m_Diag = 0;}CDiagBuffer::~CDiagBuffer(void){#if (_DEBUG > 1) if (m_Diag || dynamic_cast<CNcbiOstrstream*>(m_Stream)->pcount()) Abort();#endif delete m_Stream; m_Stream = 0;}void CDiagBuffer::DiagHandler(SDiagMessage& mess){ if ( CDiagBuffer::sm_Handler ) { CMutexGuard LOCK(s_DiagMutex); if ( CDiagBuffer::sm_Handler ) { mess.m_Prefix = GetDiagBuffer().m_PostPrefix.empty() ? 0 : GetDiagBuffer().m_PostPrefix.c_str(); CDiagBuffer::sm_Handler->Post(mess); } }}bool CDiagBuffer::SetDiag(const CNcbiDiag& diag){ if ( !m_Stream ) { return false; } // Check severity level change status if ( sm_PostSeverityChange == eDiagSC_Unknown ) { GetSeverityChangeEnabledFirstTime(); } if (diag.GetSeverity() < sm_PostSeverity || (diag.GetSeverity() == eDiag_Trace && !GetTraceEnabled())) { return false; } if (m_Diag != &diag) { if ( dynamic_cast<CNcbiOstrstream*>(m_Stream)->pcount() ) { Flush(); } m_Diag = &diag; } return true;}void CDiagBuffer::Flush(void){ if ( !m_Diag ) return; CNcbiOstrstream* ostr = dynamic_cast<CNcbiOstrstream*>(m_Stream); EDiagSev sev = m_Diag->GetSeverity(); if ( ostr->pcount() ) { const char* message = ostr->str(); size_t size = ostr->pcount(); ostr->rdbuf()->freeze(false); TDiagPostFlags flags = m_Diag->GetPostFlags(); if (sev == eDiag_Trace) { flags |= sm_TraceFlags; } else if (sev == eDiag_Fatal) { // normally only happens once, so might as well pull everything // in for the record... flags |= sm_TraceFlags | eDPF_Trace; } string dest; if (IsSetDiagPostFlag(eDPF_PreMergeLines, flags)) { string src(message,0,size); NStr::Replace(NStr::Replace(src,"\r",""),"\n",";", dest); message = dest.c_str(); size = dest.length(); } SDiagMessage mess (sev, message, size, m_Diag->GetFile(), m_Diag->GetLine(), flags, 0, m_Diag->GetErrorCode(), m_Diag->GetErrorSubCode()); DiagHandler(mess);#if defined(NCBI_COMPILER_KCC) // KCC's implementation of "freeze(false)" makes the ostrstream buffer // stuck. We need to replace the frozen stream with the new one. delete ostr; m_Stream = new CNcbiOstrstream;#endif Reset(*m_Diag); } if (sev >= sm_DieSeverity && sev != eDiag_Trace) { m_Diag = 0;#if defined(NCBI_OS_MAC) if ( g_Mac_SpecialEnvironment ) { throw runtime_error("Application aborted."); }#endif Abort(); }}bool CDiagBuffer::GetTraceEnabledFirstTime(void){ CMutexGuard LOCK(s_DiagMutex); const char* str = ::getenv(DIAG_TRACE); if (str && *str) { sm_TraceDefault = eDT_Enable; } else { sm_TraceDefault = eDT_Disable; } sm_TraceEnabled = (sm_TraceDefault == eDT_Enable); return sm_TraceEnabled;}bool CDiagBuffer::GetSeverityChangeEnabledFirstTime(void){ CMutexGuard LOCK(s_DiagMutex); if ( sm_PostSeverityChange != eDiagSC_Unknown ) { return sm_PostSeverityChange == eDiagSC_Enable; } const char* str = ::getenv(DIAG_POST_LEVEL); EDiagSev sev; if (str && *str && CNcbiDiag::StrToSeverityLevel(str, sev)) { SetDiagFixedPostLevel(sev); } else { sm_PostSeverityChange = eDiagSC_Enable; } return sm_PostSeverityChange == eDiagSC_Enable;}void CDiagBuffer::UpdatePrefix(void){ m_PostPrefix.erase(); ITERATE(TPrefixList, prefix, m_PrefixList) { if (prefix != m_PrefixList.begin()) { m_PostPrefix += "::"; } m_PostPrefix += *prefix; }}///////////////////////////////////////////////////////// CDiagMessage::void SDiagMessage::Write(string& str, TDiagWriteFlags flags) const{ CNcbiOstrstream ostr; Write(ostr, flags); ostr.put('\0'); str = ostr.str(); ostr.rdbuf()->freeze(false);}CNcbiOstream& SDiagMessage::Write(CNcbiOstream& os, TDiagWriteFlags flags) const{ if (IsSetDiagPostFlag(eDPF_MergeLines, m_Flags)) { CNcbiOstrstream ostr; string src, dest; x_Write(ostr, fNoEndl); ostr.put('\0'); src = ostr.str(); ostr.rdbuf()->freeze(false); NStr::Replace(NStr::Replace(src,"\r",""),"\n","", dest); os << dest; if ((flags & fNoEndl) == 0) { os << NcbiEndl; } return os; } else { return x_Write(os, flags); }}CNcbiOstream& SDiagMessage::x_Write(CNcbiOstream& os, TDiagWriteFlags flags) const{ // Date & time if (IsSetDiagPostFlag(eDPF_DateTime, m_Flags)) { static const char timefmt[] = "%D %T "; time_t t = time(0); char datetime[32]; struct tm* tm;#ifdef HAVE_LOCALTIME_R struct tm temp; localtime_r(&t, &temp); tm = &temp;#else tm = localtime(&t);#endif /*HAVE_LOCALTIME_R*/ NStr::strftime(datetime, sizeof(datetime), timefmt, tm); os << datetime; } // "<file>" bool print_file = (m_File && *m_File && IsSetDiagPostFlag(eDPF_File, m_Flags)); if ( print_file ) { const char* x_file = m_File; if ( !IsSetDiagPostFlag(eDPF_LongFilename, m_Flags) ) { for (const char* s = m_File; *s; s++) { if (*s == '/' || *s == '\\' || *s == ':') x_file = s + 1; } } os << '"' << x_file << '"'; } // , line <line> bool print_line = (m_Line && IsSetDiagPostFlag(eDPF_Line, m_Flags)); if ( print_line ) os << (print_file ? ", line " : "line ") << m_Line; // : if (print_file || print_line) os << ": "; // Get error code description bool have_description = false; SDiagErrCodeDescription description; if ((m_ErrCode || m_ErrSubCode) && (IsSetDiagPostFlag(eDPF_ErrCodeMessage, m_Flags) || IsSetDiagPostFlag(eDPF_ErrCodeExplanation, m_Flags) || IsSetDiagPostFlag(eDPF_ErrCodeUseSeverity, m_Flags)) && IsSetDiagErrCodeInfo()) { CDiagErrCodeInfo* info = GetDiagErrCodeInfo(); if ( info && info->GetDescription(ErrCode(m_ErrCode, m_ErrSubCode), &description) ) { have_description = true; if (IsSetDiagPostFlag(eDPF_ErrCodeUseSeverity, m_Flags) && description.m_Severity != -1 ) m_Severity = (EDiagSev)description.m_Severity; } } // <severity>: if (IsSetDiagPostFlag(eDPF_Severity, m_Flags) && (m_Severity != eDiag_Info || !IsSetDiagPostFlag(eDPF_OmitInfoSev))) os << CNcbiDiag::SeverityName(m_Severity) << ": "; // (<err_code>.<err_subcode>) or (err_text) if ((m_ErrCode || m_ErrSubCode || m_ErrText) && IsSetDiagPostFlag(eDPF_ErrCode, m_Flags)) { os << '('; if (m_ErrText) { os << m_ErrText; } else { os << m_ErrCode; if ( IsSetDiagPostFlag(eDPF_ErrSubCode, m_Flags)) { os << '.' << m_ErrSubCode; } } os << ") "; } // [<prefix1>::<prefix2>::.....] if (m_Prefix && *m_Prefix && IsSetDiagPostFlag(eDPF_Prefix, m_Flags)) os << '[' << m_Prefix << "] "; // <message> if (m_BufferLen) os.write(m_Buffer, m_BufferLen); // <err_code_message> and <err_code_explanation> if (have_description) { if (IsSetDiagPostFlag(eDPF_ErrCodeMessage, m_Flags) && !description.m_Message.empty()) os << NcbiEndl << description.m_Message << ' '; if (IsSetDiagPostFlag(eDPF_ErrCodeExplanation, m_Flags) && !description.m_Explanation.empty()) os << NcbiEndl << description.m_Explanation; } // Endl if ((flags & fNoEndl) == 0) { os << NcbiEndl; } return os;}///////////////////////////////////////////////////////// CDiagAutoPrefix::CDiagAutoPrefix::CDiagAutoPrefix(const string& prefix){ PushDiagPostPrefix(prefix.c_str());}CDiagAutoPrefix::CDiagAutoPrefix(const char* prefix){ PushDiagPostPrefix(prefix);}CDiagAutoPrefix::~CDiagAutoPrefix(void){ PopDiagPostPrefix();}///////////////////////////////////////////////////////// EXTERNstatic TDiagPostFlags s_SetDiagPostAllFlags(TDiagPostFlags& flags, TDiagPostFlags new_flags){ CMutexGuard LOCK(s_DiagMutex); TDiagPostFlags prev_flags = flags; if (new_flags & eDPF_Default) { new_flags |= prev_flags; new_flags &= ~eDPF_Default; } flags = new_flags; return prev_flags;}static void s_SetDiagPostFlag(TDiagPostFlags& flags, EDiagPostFlag flag){ if (flag == eDPF_Default) return; CMutexGuard LOCK(s_DiagMutex); flags |= flag;}static void s_UnsetDiagPostFlag(TDiagPostFlags& flags, EDiagPostFlag flag){ if (flag == eDPF_Default) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -