X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c602c59b6e623d7775c16ce6412b64b34dc5dd94..a703012aedeb8064c8294c6aeeea95e6950ad170:/include/wx/log.h diff --git a/include/wx/log.h b/include/wx/log.h index 73a8e60559..8f872af38e 100644 --- a/include/wx/log.h +++ b/include/wx/log.h @@ -43,6 +43,16 @@ typedef unsigned long wxLogLevel; #include "wx/string.h" #include "wx/strvararg.h" +// ---------------------------------------------------------------------------- +// forward declarations +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_FWD_BASE wxObject; + +#if wxUSE_GUI + class WXDLLIMPEXP_FWD_CORE wxFrame; +#endif // wxUSE_GUI + #if wxUSE_LOG #include "wx/arrstr.h" @@ -91,16 +101,6 @@ typedef unsigned long wxLogLevel; #endif #endif -// ---------------------------------------------------------------------------- -// forward declarations -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_FWD_BASE wxObject; - -#if wxUSE_GUI - class WXDLLIMPEXP_FWD_CORE wxFrame; -#endif // wxUSE_GUI - // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -289,6 +289,26 @@ private: #define wxLOG_KEY_TRACE_MASK "wx.trace_mask" +// ---------------------------------------------------------------------------- +// log record: a unit of log output +// ---------------------------------------------------------------------------- + +struct wxLogRecord +{ + wxLogRecord(wxLogLevel level_, + const wxString& msg_, + const wxLogRecordInfo& info_) + : level(level_), + msg(msg_), + info(info_) + { + } + + wxLogLevel level; + wxString msg; + wxLogRecordInfo info; +}; + // ---------------------------------------------------------------------------- // derive from this class to redirect (or suppress, or ...) log messages // normally, only a single instance of this class exists but it's not enforced @@ -308,15 +328,32 @@ public: // ---------------------- // these functions allow to completely disable all log messages or disable - // log messages at level less important than specified + // log messages at level less important than specified for the current + // thread // is logging enabled at all now? - static bool IsEnabled() { return ms_doLog; } + static bool IsEnabled() + { +#if wxUSE_THREADS + if ( !wxThread::IsMain() ) + return IsThreadLoggingEnabled(); +#endif // wxUSE_THREADS + + return ms_doLog; + } // change the flag state, return the previous one - static bool EnableLogging(bool doIt = true) - { bool doLogOld = ms_doLog; ms_doLog = doIt; return doLogOld; } + static bool EnableLogging(bool enable = true) + { +#if wxUSE_THREADS + if ( !wxThread::IsMain() ) + return EnableThreadLogging(enable); +#endif // wxUSE_THREADS + bool doLogOld = ms_doLog; + ms_doLog = enable; + return doLogOld; + } // return the current global log level static wxLogLevel GetLogLevel() { return ms_logLevel; } @@ -361,28 +398,26 @@ public: // ----------------- // flush shows all messages if they're not logged immediately (FILE - // and iostream logs don't need it, but wxGuiLog does to avoid showing + // and iostream logs don't need it, but wxLogGui does to avoid showing // 17 modal dialogs one after another) virtual void Flush(); - // flush the active target if any - static void FlushActive() - { - if ( !ms_suspendCount ) - { - wxLog *log = GetActiveTarget(); - if ( log ) - log->Flush(); - } - } + // flush the active target if any and also output any pending messages from + // background threads + static void FlushActive(); - // only one sink is active at each moment - // get current log target, will call wxApp::CreateLogTarget() to - // create one if none exists + // only one sink is active at each moment get current log target, will call + // wxAppTraits::CreateLogTarget() to create one if none exists static wxLog *GetActiveTarget(); - // change log target, pLogger may be NULL - static wxLog *SetActiveTarget(wxLog *pLogger); + // change log target, logger may be NULL + static wxLog *SetActiveTarget(wxLog *logger); + +#if wxUSE_THREADS + // change log target for the current thread only, shouldn't be called from + // the main thread as it doesn't use thread-specific log target + static wxLog *SetThreadActiveTarget(wxLog *logger); +#endif // wxUSE_THREADS // suspend the message flushing of the main target until the next call // to Resume() - this is mainly for internal use (to prevent wxYield() @@ -418,7 +453,7 @@ public: // get string trace masks: note that this is MT-unsafe if other threads can // call AddTraceMask() concurrently - static const wxArrayString& GetTraceMasks() { return ms_aTraceMasks; } + static const wxArrayString& GetTraceMasks(); // sets the time stamp string format: this is used as strftime() format // string for the log targets which add time stamps to the messages; set @@ -487,14 +522,14 @@ public: #if WXWIN_COMPATIBILITY_2_6 // this function doesn't do anything any more, don't call it - wxDEPRECATED_INLINE( - static wxChar *SetLogBuffer(wxChar *, size_t = 0), return NULL; + static wxDEPRECATED_INLINE( + wxChar *SetLogBuffer(wxChar *, size_t = 0), return NULL; ); #endif // WXWIN_COMPATIBILITY_2_6 // don't use integer masks any more, use string trace masks instead #if WXWIN_COMPATIBILITY_2_8 - wxDEPRECATED_INLINE( static void SetTraceMask(wxTraceMask ulMask), + static wxDEPRECATED_INLINE( void SetTraceMask(wxTraceMask ulMask), ms_ulTraceMask = ulMask; ) // this one can't be marked deprecated as it's used in our own wxLogger @@ -560,9 +595,31 @@ protected: unsigned LogLastRepeatIfNeeded(); private: - // implement of LogLastRepeatIfNeeded(): it assumes that the - // caller had already locked GetPreviousLogCS() - unsigned LogLastRepeatIfNeededUnlocked(); +#if wxUSE_THREADS + // called from FlushActive() to really log any buffered messages logged + // from the other threads + void FlushThreadMessages(); + + // these functions are called for non-main thread only by IsEnabled() and + // EnableLogging() respectively + static bool IsThreadLoggingEnabled(); + static bool EnableThreadLogging(bool enable = true); +#endif // wxUSE_THREADS + + // get the active log target for the main thread, auto-creating it if + // necessary + // + // this is called from GetActiveTarget() and OnLog() when they're called + // from the main thread + static wxLog *GetMainThreadActiveTarget(); + + // called from OnLog() if it's called from the main thread or if we have a + // (presumably MT-safe) thread-specific logger and by FlushThreadMessages() + // when it plays back the buffered messages logged from the other threads + void CallDoLogNow(wxLogLevel level, + const wxString& msg, + const wxLogRecordInfo& info); + // static variables // ---------------- @@ -587,9 +644,6 @@ private: #if WXWIN_COMPATIBILITY_2_8 static wxTraceMask ms_ulTraceMask; // controls wxLogTrace behaviour #endif // WXWIN_COMPATIBILITY_2_8 - - // currently enabled trace masks - static wxArrayString ms_aTraceMasks; }; // ---------------------------------------------------------------------------- @@ -806,12 +860,12 @@ public: // indicates that we may have an extra first argument preceding the format // string and that if we do have it, we should store it in m_info using the // given key (while by default 0 value will be used) - wxLogger& MaybeStore(const wxString& key) + wxLogger& MaybeStore(const wxString& key, wxUIntPtr value = 0) { wxASSERT_MSG( m_optKey.empty(), "can only have one optional value" ); m_optKey = key; - m_info.StoreValue(key, 0); + m_info.StoreValue(key, value); return *this; } @@ -844,6 +898,16 @@ public: LogV(format, argptr); } + void LogVTrace(const wxString& mask, const wxString& format, va_list argptr) + { + if ( !wxLog::IsAllowedTraceMask(mask) ) + return; + + Store(wxLOG_KEY_TRACE_MASK, mask); + + LogV(format, argptr); + } + // vararg functions used by wxLogXXX(): @@ -1140,7 +1204,7 @@ private: void DoCallOnLog(const wxString& format, va_list argptr) { - wxLog::OnLog(m_level, wxString::FormatV(format, argptr), m_info); + DoCallOnLog(m_level, format, argptr); } @@ -1240,7 +1304,7 @@ WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); wxDO_LOG(level) // wxLogFatalError() is special as it can't be disabled -#define wxLogFatalError wxDO_LOG(FatalError) +#define wxLogFatalError wxDO_LOG(FatalError) #define wxVLogFatalError(format, argptr) wxDO_LOGV(FatalError, format, argptr) #define wxLogError wxDO_LOG_IF_ENABLED(Error) @@ -1287,19 +1351,30 @@ WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); // wxLogSysError() needs to stash the error code value in the log record info // so it needs special handling too; additional complications arise because the // error code may or not be present as the first argument +// +// notice that we unfortunately can't avoid the call to wxSysErrorCode() even +// though it may be unneeded if an explicit error code is passed to us because +// the message might not be logged immediately (e.g. it could be queued for +// logging from the main thread later) and so we can't to wait until it is +// logged to determine whether we have last error or not as it will be too late +// and it will have changed already by then (in fact it even changes when +// wxString::Format() is called because of vsnprintf() inside it so it can +// change even much sooner) #define wxLOG_KEY_SYS_ERROR_CODE "wx.sys_error" #define wxLogSysError \ if ( !wxLog::IsLevelEnabled(wxLOG_Error, wxLOG_COMPONENT) ) \ {} \ else \ - wxMAKE_LOGGER(Error).MaybeStore(wxLOG_KEY_SYS_ERROR_CODE).Log + wxMAKE_LOGGER(Error).MaybeStore(wxLOG_KEY_SYS_ERROR_CODE, \ + wxSysErrorCode()).Log // unfortunately we can't have overloaded macros so we can't define versions // both with and without error code argument and have to rely on LogV() // overloads in wxLogger to select between them #define wxVLogSysError \ - wxMAKE_LOGGER(Error).MaybeStore(wxLOG_KEY_SYS_ERROR_CODE).LogV + wxMAKE_LOGGER(Error).MaybeStore(wxLOG_KEY_SYS_ERROR_CODE, \ + wxSysErrorCode()).LogV #if wxUSE_GUI // wxLogStatus() is similar to wxLogSysError() as it allows to optionally @@ -1337,24 +1412,24 @@ WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); // WX_WATCOM_ONLY_CODE is needed to work around // http://bugzilla.openwatcom.org/show_bug.cgi?id=351 #define wxDEFINE_EMPTY_LOG_FUNCTION(level) \ - WX_DEFINE_VARARG_FUNC_NOP(wxLog##level, 1, (const wxString&)) \ + WX_DEFINE_VARARG_FUNC_NOP(wxLog##level, 1, (const wxFormatString&)) \ WX_WATCOM_ONLY_CODE( \ WX_DEFINE_VARARG_FUNC_NOP(wxLog##level, 1, (const char*)) \ WX_DEFINE_VARARG_FUNC_NOP(wxLog##level, 1, (const wchar_t*)) \ WX_DEFINE_VARARG_FUNC_NOP(wxLog##level, 1, (const wxCStrData&)) \ ) \ - inline void wxVLog##level(const wxString& WXUNUSED(format), \ + inline void wxVLog##level(const wxFormatString& WXUNUSED(format), \ va_list WXUNUSED(argptr)) { } \ #define wxDEFINE_EMPTY_LOG_FUNCTION2(level, argclass) \ - WX_DEFINE_VARARG_FUNC_NOP(wxLog##level, 2, (argclass, const wxString&)) \ + WX_DEFINE_VARARG_FUNC_NOP(wxLog##level, 2, (argclass, const wxFormatString&)) \ WX_WATCOM_OR_MINGW_ONLY_CODE( \ WX_DEFINE_VARARG_FUNC_NOP(wxLog##level, 2, (argclass, const char*)) \ WX_DEFINE_VARARG_FUNC_NOP(wxLog##level, 2, (argclass, const wchar_t*)) \ WX_DEFINE_VARARG_FUNC_NOP(wxLog##level, 2, (argclass, const wxCStrData&)) \ ) \ inline void wxVLog##level(argclass WXUNUSED(arg), \ - const wxString& WXUNUSED(format), \ + const wxFormatString& WXUNUSED(format), \ va_list WXUNUSED(argptr)) {} wxDEFINE_EMPTY_LOG_FUNCTION(FatalError); @@ -1421,7 +1496,7 @@ public: #ifdef HAVE_VARIADIC_MACROS #define wxLogDebug(fmt, ...) wxLogNop() #else // !HAVE_VARIADIC_MACROS - WX_DEFINE_VARARG_FUNC_NOP(wxLogDebug, 1, (const wxString&)) + WX_DEFINE_VARARG_FUNC_NOP(wxLogDebug, 1, (const wxFormatString&)) #endif #endif // wxUSE_LOG_DEBUG/!wxUSE_LOG_DEBUG @@ -1431,6 +1506,11 @@ public: {} \ else \ wxMAKE_LOGGER(Trace).LogTrace + #define wxVLogTrace \ + if ( !wxLog::IsLevelEnabled(wxLOG_Trace, wxLOG_COMPONENT) ) \ + {} \ + else \ + wxMAKE_LOGGER(Trace).LogVTrace #else // !wxUSE_LOG_TRACE #define wxVLogTrace(mask, fmt, valist) wxLogNop() @@ -1438,9 +1518,9 @@ public: #define wxLogTrace(mask, fmt, ...) wxLogNop() #else // !HAVE_VARIADIC_MACROS #if WXWIN_COMPATIBILITY_2_8 - WX_DEFINE_VARARG_FUNC_NOP(wxLogTrace, 2, (wxTraceMask, const wxString&)) + WX_DEFINE_VARARG_FUNC_NOP(wxLogTrace, 2, (wxTraceMask, const wxFormatString&)) #endif - WX_DEFINE_VARARG_FUNC_NOP(wxLogTrace, 2, (const wxString&, const wxString&)) + WX_DEFINE_VARARG_FUNC_NOP(wxLogTrace, 2, (const wxString&, const wxFormatString&)) #ifdef __WATCOMC__ // workaround for http://bugzilla.openwatcom.org/show_bug.cgi?id=351 WX_DEFINE_VARARG_FUNC_NOP(wxLogTrace, 2, (const char*, const char*)) @@ -1490,5 +1570,14 @@ wxSafeShowMessage(const wxString& title, const wxString& text); #undef WX_WATCOM_ONLY_CODE #endif +// macro which disables debug logging in release builds: this is done by +// default by wxIMPLEMENT_APP() so usually it doesn't need to be used explicitly +#if defined(NDEBUG) && wxUSE_LOG_DEBUG + #define wxDISABLE_DEBUG_LOGGING_IN_RELEASE_BUILD() \ + wxLog::SetLogLevel(wxLOG_Info) +#else // !NDEBUG + #define wxDISABLE_DEBUG_LOGGING_IN_RELEASE_BUILD() +#endif // NDEBUG/!NDEBUG + #endif // _WX_LOG_H_