X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/af58844636f51ca9c9350c66de3baf427d3e8646..edaadd8cd2fd81d251559d3451db4897995554b8:/include/wx/log.h diff --git a/include/wx/log.h b/include/wx/log.h index 60b6e8b620..c7bbf0b2db 100644 --- a/include/wx/log.h +++ b/include/wx/log.h @@ -78,10 +78,25 @@ typedef unsigned long wxLogLevel; #endif #endif // wxUSE_LOG_TRACE +// wxLOG_COMPONENT identifies the component which generated the log record and +// can be #define'd to a user-defined value when compiling the user code to use +// component-based filtering (see wxLog::SetComponentLevel()) +#ifndef wxLOG_COMPONENT + // this is a variable and not a macro in order to allow the user code to + // just #define wxLOG_COMPONENT without #undef'ining it first + extern WXDLLIMPEXP_DATA_BASE(const char *) wxLOG_COMPONENT; + + #ifdef WXBUILDING + #define wxLOG_COMPONENT "wx" + #endif +#endif + // ---------------------------------------------------------------------------- // forward declarations // ---------------------------------------------------------------------------- +class WXDLLIMPEXP_FWD_BASE wxObject; + #if wxUSE_GUI class WXDLLIMPEXP_FWD_CORE wxFrame; #endif // wxUSE_GUI @@ -131,18 +146,20 @@ public: // default ctor creates an uninitialized object wxLogRecordInfo() { - memset(this, 0, sizeof(this)); + memset(this, 0, sizeof(*this)); } // normal ctor, used by wxLogger specifies the location of the log // statement; its time stamp and thread id are set up here wxLogRecordInfo(const char *filename_, int line_, - const char *func_) + const char *func_, + const char *component_) { filename = filename_; func = func_; line = line_; + component = component_; timestamp = time(NULL); @@ -186,6 +203,10 @@ public: // if the compiler doesn't support __FUNCTION__) const char *func; + // the name of the component which generated this message, may be NULL if + // not set (i.e. wxLOG_COMPONENT not defined) + const char *component; + // time of record generation time_t timestamp; @@ -248,7 +269,7 @@ public: private: void Copy(const wxLogRecordInfo& other) { - memcpy(this, &other, sizeof(wxLogRecordInfo)); + memcpy(this, &other, sizeof(*this)); if ( other.m_data ) m_data = new ExtraData(*other.m_data); } @@ -268,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 @@ -283,44 +324,100 @@ public: virtual ~wxLog(); - // these functions allow to completely disable all log messages + // log messages selection + // ---------------------- + + // these functions allow to completely disable all log messages or disable + // 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 - // is logging at this level enabled? - static bool IsLevelEnabled(wxLogLevel level) - { return IsEnabled() && level <= ms_logLevel; } + 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; } + + // set global log level: messages with level > logLevel will not be logged + static void SetLogLevel(wxLogLevel logLevel) { ms_logLevel = logLevel; } + + // set the log level for the given component + static void SetComponentLevel(const wxString& component, wxLogLevel level); + + // return the effective log level for this component, falling back to + // parent component and to the default global log level if necessary + // + // NB: component argument is passed by value and not const reference in an + // attempt to encourage compiler to avoid an extra copy: as we modify + // the component internally, we'd create one anyhow and like this it + // can be avoided if the string is a temporary anyhow + static wxLogLevel GetComponentLevel(wxString component); + + + // is logging of messages from this component enabled at this level? + // + // usually always called with wxLOG_COMPONENT as second argument + static bool IsLevelEnabled(wxLogLevel level, wxString component) + { + return IsEnabled() && level <= GetComponentLevel(component); + } + + + // enable/disable messages at wxLOG_Verbose level (only relevant if the + // current log level is greater or equal to it) + // + // notice that verbose mode can be activated by the standard command-line + // '--verbose' option + static void SetVerbose(bool bVerbose = true) { ms_bVerbose = bVerbose; } + + // check if verbose messages are enabled + static bool GetVerbose() { return ms_bVerbose; } + // message buffering + // ----------------- // flush shows all messages if they're not logged immediately (FILE // and iostream logs don't need it, but wxGuiLog 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() @@ -330,14 +427,6 @@ public: // must be called for each Suspend()! static void Resume() { ms_suspendCount--; } - // functions controlling the default wxLog behaviour - // verbose mode is activated by standard command-line '--verbose' - // option - static void SetVerbose(bool bVerbose = true) { ms_bVerbose = bVerbose; } - - // Set log level. Log messages with level > logLevel will not be logged. - static void SetLogLevel(wxLogLevel logLevel) { ms_logLevel = logLevel; } - // should GetActiveTarget() try to create a new log object if the // current is NULL? static void DontCreateOnDemand(); @@ -375,17 +464,9 @@ public: static void DisableTimestamp() { SetTimestamp(wxEmptyString); } - // accessors - - // gets the verbose status - static bool GetVerbose() { return ms_bVerbose; } - // is this trace mask in the list? static bool IsAllowedTraceMask(const wxString& mask); - // return the current loglevel limit - static wxLogLevel GetLogLevel() { return ms_logLevel; } - // get the current timestamp format string (maybe empty) static const wxString& GetTimestamp() { return ms_timestamp; } @@ -450,8 +531,10 @@ public: #if WXWIN_COMPATIBILITY_2_8 wxDEPRECATED_INLINE( static void SetTraceMask(wxTraceMask ulMask), ms_ulTraceMask = ulMask; ) - wxDEPRECATED_BUT_USED_INTERNALLY_INLINE( static wxTraceMask GetTraceMask(), - return ms_ulTraceMask; ) + + // this one can't be marked deprecated as it's used in our own wxLogger + // below but it still is deprecated and shouldn't be used + static wxTraceMask GetTraceMask() { return ms_ulTraceMask; } #endif // WXWIN_COMPATIBILITY_2_8 protected: @@ -512,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 // ---------------- @@ -738,9 +843,10 @@ public: wxLogger(wxLogLevel level, const char *filename, int line, - const char *func) + const char *func, + const char *component) : m_level(level), - m_info(filename, line, func) + m_info(filename, line, func, component) { } @@ -774,7 +880,8 @@ public: void LogV(const wxString& format, va_list argptr) { // remember that fatal errors can't be disabled - if ( m_level == wxLOG_FatalError || wxLog::IsLevelEnabled(m_level) ) + if ( m_level == wxLOG_FatalError || + wxLog::IsLevelEnabled(m_level, m_info.component) ) DoCallOnLog(format, argptr); } @@ -819,10 +926,15 @@ public: DoLogWithNum, DoLogWithNumUtf8 ) + // unfortunately we can't use "void *" here as we get overload ambiguities + // with Log(wxFormatString, ...) when the first argument is a "char *" or + // "wchar_t *" then -- so we only allow passing wxObject here, which is + // ugly but fine in practice as this overload is only used by wxLogStatus() + // whose first argument is a wxFrame WX_DEFINE_VARARG_FUNC_VOID ( Log, - 2, (void *, const wxFormatString&), + 2, (wxObject *, const wxFormatString&), DoLogWithPtr, DoLogWithPtrUtf8 ) @@ -838,8 +950,8 @@ public: ) // special versions for wxLogTrace() which is passed either string or - // integer (TODO) mask as first argument determining whether the message - // should be logged or not + // integer mask as first argument determining whether the message should be + // logged or not WX_DEFINE_VARARG_FUNC_VOID ( LogTrace, @@ -847,6 +959,15 @@ public: DoLogTrace, DoLogTraceUtf8 ) +#if WXWIN_COMPATIBILITY_2_8 + WX_DEFINE_VARARG_FUNC_VOID + ( + LogTrace, + 2, (wxTraceMask, const wxFormatString&), + DoLogTraceMask, DoLogTraceMaskUtf8 + ) +#endif // WXWIN_COMPATIBILITY_2_8 + #ifdef __WATCOMC__ // workaround for http://bugzilla.openwatcom.org/show_bug.cgi?id=351 WX_VARARG_WATCOM_WORKAROUND(void, Log, @@ -876,16 +997,16 @@ public: (f1, wxFormatString(f2))) WX_VARARG_WATCOM_WORKAROUND(void, Log, - 2, (void *, const wxString&), + 2, (wxObject *, const wxString&), (f1, wxFormatString(f2))) WX_VARARG_WATCOM_WORKAROUND(void, Log, - 2, (void *, const wxCStrData&), + 2, (wxObject *, const wxCStrData&), (f1, wxFormatString(f2))) WX_VARARG_WATCOM_WORKAROUND(void, Log, - 2, (void *, const char *), + 2, (wxObject *, const char *), (f1, wxFormatString(f2))) WX_VARARG_WATCOM_WORKAROUND(void, Log, - 2, (void *, const wchar_t *), + 2, (wxObject *, const wchar_t *), (f1, wxFormatString(f2))) WX_VARARG_WATCOM_WORKAROUND(void, LogAtLevel, @@ -913,6 +1034,21 @@ public: WX_VARARG_WATCOM_WORKAROUND(void, LogTrace, 2, (const wxString&, const wchar_t *), (f1, wxFormatString(f2))) + +#if WXWIN_COMPATIBILITY_2_8 + WX_VARARG_WATCOM_WORKAROUND(void, LogTrace, + 2, (wxTraceMask, wxTraceMask), + (f1, wxFormatString(f2))) + WX_VARARG_WATCOM_WORKAROUND(void, LogTrace, + 2, (wxTraceMask, const wxCStrData&), + (f1, wxFormatString(f2))) + WX_VARARG_WATCOM_WORKAROUND(void, LogTrace, + 2, (wxTraceMask, const char *), + (f1, wxFormatString(f2))) + WX_VARARG_WATCOM_WORKAROUND(void, LogTrace, + 2, (wxTraceMask, const wchar_t *), + (f1, wxFormatString(f2))) +#endif // WXWIN_COMPATIBILITY_2_8 #endif // __WATCOMC__ private: @@ -947,7 +1083,7 @@ private: void DoLogAtLevel(wxLogLevel level, const wxChar *format, ...) { - if ( !wxLog::IsLevelEnabled(level) ) + if ( !wxLog::IsLevelEnabled(level, m_info.component) ) return; va_list argptr; @@ -968,6 +1104,21 @@ private: DoCallOnLog(format, argptr); va_end(argptr); } + +#if WXWIN_COMPATIBILITY_2_8 + void DoLogTraceMask(wxTraceMask mask, const wxChar *format, ...) + { + if ( (wxLog::GetTraceMask() & mask) != mask ) + return; + + Store(wxLOG_KEY_TRACE_MASK, mask); + + va_list argptr; + va_start(argptr, format); + DoCallOnLog(format, argptr); + va_end(argptr); + } +#endif // WXWIN_COMPATIBILITY_2_8 #endif // !wxUSE_UTF8_LOCALE_ONLY #if wxUSE_UNICODE_UTF8 @@ -1001,7 +1152,7 @@ private: void DoLogAtLevelUtf8(wxLogLevel level, const char *format, ...) { - if ( !wxLog::IsLevelEnabled(level) ) + if ( !wxLog::IsLevelEnabled(level, m_info.component) ) return; va_list argptr; @@ -1022,6 +1173,21 @@ private: DoCallOnLog(format, argptr); va_end(argptr); } + +#if WXWIN_COMPATIBILITY_2_8 + void DoLogTraceMaskUtf8(wxTraceMask mask, const char *format, ...) + { + if ( (wxLog::GetTraceMask() & mask) != mask ) + return; + + Store(wxLOG_KEY_TRACE_MASK, mask); + + va_list argptr; + va_start(argptr, format); + DoCallOnLog(format, argptr); + va_end(argptr); + } +#endif // WXWIN_COMPATIBILITY_2_8 #endif // wxUSE_UNICODE_UTF8 void DoCallOnLog(wxLogLevel level, const wxString& format, va_list argptr) @@ -1092,7 +1258,7 @@ WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); // creates wxLogger object for the current location #define wxMAKE_LOGGER(level) \ - wxLogger(wxLOG_##level, __FILE__, __LINE__, __WXFUNCTION__) + wxLogger(wxLOG_##level, __FILE__, __LINE__, __WXFUNCTION__, wxLOG_COMPONENT) // this macro generates the expression which logs whatever follows it in // parentheses at the level specified as argument @@ -1125,7 +1291,7 @@ WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); // easily fixed by adding curly braces around wxLogError() and at least // the code still does do the right thing. #define wxDO_LOG_IF_ENABLED(level) \ - if ( !wxLog::IsLevelEnabled(wxLOG_##level) ) \ + if ( !wxLog::IsLevelEnabled(wxLOG_##level, wxLOG_COMPONENT) ) \ {} \ else \ wxDO_LOG(level) @@ -1145,12 +1311,14 @@ WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); // this one is special as it only logs if we're in verbose mode #define wxLogVerbose \ - if ( !(wxLog::IsLevelEnabled(wxLOG_Info) && wxLog::GetVerbose()) ) \ + if ( !(wxLog::IsLevelEnabled(wxLOG_Info, wxLOG_COMPONENT) && \ + wxLog::GetVerbose()) ) \ {} \ else \ wxDO_LOG(Info) #define wxVLogVerbose(format, argptr) \ - if ( !(wxLog::IsLevelEnabled(wxLOG_Info) && wxLog::GetVerbose()) ) \ + if ( !(wxLog::IsLevelEnabled(wxLOG_Info, wxLOG_COMPONENT) && \ + wxLog::GetVerbose()) ) \ {} \ else \ wxDO_LOGV(Info, format, argptr) @@ -1167,7 +1335,7 @@ WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); // always evaluated, unlike for the other log functions #define wxLogGeneric wxMAKE_LOGGER(Max).LogAtLevel #define wxVLogGeneric(level, format, argptr) \ - if ( !wxLog::IsLevelEnabled(wxLOG_##level) ) \ + if ( !wxLog::IsLevelEnabled(wxLOG_##level, wxLOG_COMPONENT) ) \ {} \ else \ wxDO_LOGV(level, format, argptr) @@ -1179,7 +1347,7 @@ WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); #define wxLOG_KEY_SYS_ERROR_CODE "wx.sys_error" #define wxLogSysError \ - if ( !wxLog::IsLevelEnabled(wxLOG_Error) ) \ + if ( !wxLog::IsLevelEnabled(wxLOG_Error, wxLOG_COMPONENT) ) \ {} \ else \ wxMAKE_LOGGER(Error).MaybeStore(wxLOG_KEY_SYS_ERROR_CODE).Log @@ -1196,7 +1364,7 @@ WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0); #define wxLOG_KEY_FRAME "wx.frame" #define wxLogStatus \ - if ( !wxLog::IsLevelEnabled(wxLOG_Status) ) \ + if ( !wxLog::IsLevelEnabled(wxLOG_Status, wxLOG_COMPONENT) ) \ {} \ else \ wxMAKE_LOGGER(Status).MaybeStore(wxLOG_KEY_FRAME).Log @@ -1316,7 +1484,7 @@ public: #if wxUSE_LOG_TRACE #define wxLogTrace \ - if ( !wxLog::IsLevelEnabled(wxLOG_Trace) ) \ + if ( !wxLog::IsLevelEnabled(wxLOG_Trace, wxLOG_COMPONENT) ) \ {} \ else \ wxMAKE_LOGGER(Trace).LogTrace