X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/af58844636f51ca9c9350c66de3baf427d3e8646..c564ca3c975aba89f8b911ace0f240c0aaf4cf73:/include/wx/log.h?ds=sidebyside diff --git a/include/wx/log.h b/include/wx/log.h index 60b6e8b620..90dde5e6b4 100644 --- a/include/wx/log.h +++ b/include/wx/log.h @@ -29,7 +29,7 @@ typedef unsigned long wxLogLevel; #define wxTraceResAlloc 0x0004 // trace GDI resource allocation #define wxTraceRefCount 0x0008 // trace various ref counting operations - #ifdef __WXMSW__ + #ifdef __WINDOWS__ #define wxTraceOleCalls 0x0100 // OLE interface calls #endif @@ -43,15 +43,23 @@ 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" -#ifndef __WXPALMOS5__ #ifndef __WXWINCE__ #include // for time_t #endif -#endif // ! __WXPALMOS5__ #include "wx/dynarray.h" #include "wx/hashmap.h" @@ -78,13 +86,18 @@ typedef unsigned long wxLogLevel; #endif #endif // wxUSE_LOG_TRACE -// ---------------------------------------------------------------------------- -// forward declarations -// ---------------------------------------------------------------------------- +// 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; -#if wxUSE_GUI - class WXDLLIMPEXP_FWD_CORE wxFrame; -#endif // wxUSE_GUI + #ifdef WXBUILDING + #define wxLOG_COMPONENT "wx" + #endif +#endif // ---------------------------------------------------------------------------- // constants @@ -115,7 +128,7 @@ enum wxLogLevelValues #define wxTRACE_ResAlloc wxT("resalloc") // trace GDI resource allocation #define wxTRACE_RefCount wxT("refcount") // trace various ref counting operations -#ifdef __WXMSW__ +#ifdef __WINDOWS__ #define wxTRACE_OleCalls wxT("ole") // OLE interface calls #endif @@ -131,18 +144,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 +201,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 +267,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 +287,54 @@ 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 customize format of log messages. +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxLogFormatter +{ +public: + // Default constructor. + wxLogFormatter() { } + + // Trivial but virtual destructor for the base class. + virtual ~wxLogFormatter() { } + + + // Override this method to implement custom formatting of the given log + // record. The default implementation simply prepends a level-dependent + // prefix to the message and optionally adds a time stamp. + virtual wxString Format(wxLogLevel level, + const wxString& msg, + const wxLogRecordInfo& info) const; + +protected: + // Override this method to change just the time stamp formatting. It is + // called by default Format() implementation. + virtual wxString FormatTime(time_t t) const; +}; + + // ---------------------------------------------------------------------------- // 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 @@ -277,50 +344,106 @@ class WXDLLIMPEXP_BASE wxLog { public: // ctor - wxLog() { } + wxLog() : m_formatter(new wxLogFormatter) { } // make dtor virtual for all derived classes 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 + // 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() @@ -330,14 +453,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(); @@ -364,7 +479,27 @@ 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(); + + // is this trace mask in the list? + static bool IsAllowedTraceMask(const wxString& mask); + + + // log formatting + // ----------------- + + // Change wxLogFormatter object used by wxLog to format the log messages. + // + // wxLog takes ownership of the pointer passed in but the caller is + // responsible for deleting the returned pointer. + wxLogFormatter* SetFormatter(wxLogFormatter* formatter); + + + // All the time stamp related functions below only work when the default + // wxLogFormatter is being used. Defining a custom formatter overrides them + // as it could use its own time stamp format or format messages without + // using time stamp at all. + // 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 @@ -375,17 +510,6 @@ 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; } @@ -394,9 +518,10 @@ public: // helpers: all functions in this section are mostly for internal use only, // don't call them from your code even if they are not formally deprecated - // put the time stamp into the string if ms_timestamp != NULL (don't - // change it otherwise) + // put the time stamp into the string if ms_timestamp is not empty (don't + // change it otherwise); the first overload uses the current time. static void TimeStamp(wxString *str); + static void TimeStamp(wxString *str, time_t t); // these methods should only be called from derived classes DoLogRecord(), // DoLogTextAtLevel() and DoLogText() implementations respectively and @@ -441,17 +566,19 @@ 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; ) - 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 +639,37 @@ 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); + + + // variables + // ---------------- + + wxLogFormatter *m_formatter; // We own this pointer. + // static variables // ---------------- @@ -539,9 +694,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; }; // ---------------------------------------------------------------------------- @@ -738,9 +890,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) { } @@ -757,12 +910,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; } @@ -774,7 +927,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); } @@ -794,6 +948,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(): @@ -819,10 +983,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 +1007,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 +1016,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 +1054,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 +1091,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 +1140,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 +1161,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 +1209,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 +1230,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) @@ -1031,7 +1254,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); } @@ -1092,7 +1315,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,13 +1348,13 @@ 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) // 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) @@ -1145,12 +1368,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 +1392,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) @@ -1176,19 +1401,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) ) \ + 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 @@ -1196,7 +1432,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 @@ -1226,24 +1462,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); @@ -1310,16 +1546,21 @@ 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 #if wxUSE_LOG_TRACE #define wxLogTrace \ - if ( !wxLog::IsLevelEnabled(wxLOG_Trace) ) \ + if ( !wxLog::IsLevelEnabled(wxLOG_Trace, wxLOG_COMPONENT) ) \ {} \ 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() @@ -1327,9 +1568,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*)) @@ -1379,5 +1620,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_