manual for more details.
- wxTreeCtrl::GetSelection now asserts if the tree has the wxTR_MULTIPLE style.
- Instead use GetSelections() for multiple items; or if you want only the
+ Instead use GetSelections() for multiple items; or if you want only the
single item last touched, the new wxTreeCtrl::GetFocusedItem.
+- Custom log targets should be updated to override wxLog::DoLogRecord() method
+ instead of DoLog() or DoLogString() and must be updated if they call the base
+ class versions of these functions as this won't work any more; please see the
+ documentation of wxLog for more information.
+
Changes in behaviour which may result in compilation errors
-----------------------------------------------------------
protected:
// implement sink function
- virtual void DoLogString(const wxString& szString, time_t t);
-
- wxSUPPRESS_DOLOGSTRING_HIDE_WARNING()
+ virtual void DoLogText(const wxString& msg);
private:
// the control we use
virtual void Flush();
protected:
- virtual void DoLog(wxLogLevel level, const wxString& szString, time_t t);
-
- wxSUPPRESS_DOLOG_HIDE_WARNING()
+ virtual void DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info);
// return the title to be used for the log dialog, depending on m_bErrors
// and m_bWarnings values
virtual void OnFrameDelete(wxFrame *frame);
protected:
- virtual void DoLog(wxLogLevel level, const wxString& szString, time_t t);
- virtual void DoLogString(const wxString& szString, time_t t);
-
- wxSUPPRESS_DOLOG_HIDE_WARNING()
- wxSUPPRESS_DOLOGSTRING_HIDE_WARNING()
+ virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg);
private:
wxLogFrame *m_pLogFrame; // the log frame
#include "wx/dynarray.h"
+#if wxUSE_THREADS
+ #include "wx/thread.h"
+#endif // wxUSE_THREADS
+
// wxUSE_LOG_DEBUG enables the debug log messages
#ifndef wxUSE_LOG_DEBUG
#if wxDEBUG_LEVEL
#include "wx/iosfwrap.h"
+// ----------------------------------------------------------------------------
+// information about a log record, i.e. unit of log output
+// ----------------------------------------------------------------------------
+
+struct wxLogRecordInfo
+{
+ wxLogRecordInfo()
+ {
+ timestamp = 0;
+
+#if wxUSE_THREADS
+ threadId = 0;
+#endif // wxUSE_THREADS
+ }
+
+ // default copy ctor, assignment operator and dtor are ok
+
+
+ // time of record generation
+ time_t timestamp;
+
+#if wxUSE_THREADS
+ // id of the thread which logged this record
+ wxThreadIdType threadId;
+#endif // wxUSE_THREADS
+};
+
// ----------------------------------------------------------------------------
// 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
{
public:
// ctor
- wxLog(){}
+ wxLog() { }
+
+ // make dtor virtual for all derived classes
+ virtual ~wxLog();
+
// these functions allow to completely disable all log messages
static bool EnableLogging(bool doIt = true)
{ bool doLogOld = ms_doLog; ms_doLog = doIt; return doLogOld; }
- // static sink function - see DoLog() for function to overload in the
- // derived classes
- static void OnLog(wxLogLevel level, const wxString& szString, time_t t);
-
// message buffering
// flush shows all messages if they're not logged immediately (FILE
static void Resume() { ms_suspendCount--; }
// functions controlling the default wxLog behaviour
- // verbose mode is activated by standard command-line '-verbose'
+ // verbose mode is activated by standard command-line '--verbose'
// option
static void SetVerbose(bool bVerbose = true) { ms_bVerbose = bVerbose; }
static const wxString& GetTimestamp() { return ms_timestamp; }
- // helpers
+
+ // 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)
static void TimeStamp(wxString *str);
- // this method should only be called from derived classes DoLog()
- // implementations and shouldn't be called directly, use logging functions
- // instead
- void Log(wxLogLevel level, const wxString& msg, time_t t)
+ // these methods should only be called from derived classes DoLogRecord(),
+ // DoLogTextAtLevel() and DoLogText() implementations respectively and
+ // shouldn't be called directly, use logging functions instead
+ void LogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info)
{
- DoLog(level, msg, t);
+ DoLogRecord(level, msg, info);
}
- // make dtor virtual for all derived classes
- virtual ~wxLog();
+ void LogTextAtLevel(wxLogLevel level, const wxString& msg)
+ {
+ DoLogTextAtLevel(level, msg);
+ }
+
+ void LogText(const wxString& msg)
+ {
+ DoLogText(msg);
+ }
+
+ // this is a helper used by wxLogXXX() functions, don't call it directly
+ // and see DoLog() for function to overload in the derived classes
+ static void OnLog(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info);
+
+ // version called when no information about the location of the log record
+ // generation is available (but the time stamp is), it mainly exists for
+ // backwards compatibility, don't use it in new code
+ static void OnLog(wxLogLevel level, const wxString& msg, time_t t);
+
+ // a helper calling the above overload with current time
+ static void OnLog(wxLogLevel level, const wxString& msg)
+ {
+ OnLog(level, msg, time(NULL));
+ }
// this method exists for backwards compatibility only, don't use
#if WXWIN_COMPATIBILITY_2_6
// this function doesn't do anything any more, don't call it
- wxDEPRECATED( static wxChar *SetLogBuffer(wxChar *buf, size_t size = 0) );
-#endif
+ wxDEPRECATED_INLINE(
+ static 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
#endif // WXWIN_COMPATIBILITY_2_8
protected:
- // the logging functions that can be overridden
-
- // default DoLog() prepends the time stamp and a prefix corresponding
- // to the message to szString and then passes it to DoLogString()
- virtual void DoLog(wxLogLevel level, const wxString& szString, time_t t);
+ // the logging functions that can be overridden: DoLogRecord() is called
+ // for every "record", i.e. a unit of log output, to be logged and by
+ // default formats the message and passes it to DoLogTextAtLevel() which in
+ // turn passes it to DoLogText() by default
+
+ // override this method if you want to change message formatting or do
+ // dynamic filtering
+ virtual void DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info);
+
+ // override this method to redirect output to different channels depending
+ // on its level only; if even the level doesn't matter, override
+ // DoLogText() instead
+ virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg);
+
+ // this function is not pure virtual as it might not be needed if you do
+ // the logging in overridden DoLogRecord() or DoLogTextAtLevel() directly
+ // but if you do not override them in your derived class you must override
+ // this one as the default implementation of it simply asserts
+ virtual void DoLogText(const wxString& msg);
+
+
+ // the rest of the functions are for backwards compatibility only, don't
+ // use them in new code; if you're updating your existing code you need to
+ // switch to overriding DoLogRecord/Text() above (although as long as these
+ // functions exist, log classes using them will continue to work)
#if WXWIN_COMPATIBILITY_2_8
- // these shouldn't be used by new code
wxDEPRECATED_BUT_USED_INTERNALLY(
virtual void DoLog(wxLogLevel level, const char *szString, time_t t)
);
wxDEPRECATED_BUT_USED_INTERNALLY(
virtual void DoLog(wxLogLevel level, const wchar_t *wzString, time_t t)
);
-#endif // WXWIN_COMPATIBILITY_2_8
-
- void LogString(const wxString& szString, time_t t)
- { DoLogString(szString, t); }
- // default DoLogString does nothing but is not pure virtual because if
- // you override DoLog() you might not need it at all
- virtual void DoLogString(const wxString& szString, time_t t);
-#if WXWIN_COMPATIBILITY_2_8
// these shouldn't be used by new code
- virtual void DoLogString(const char *WXUNUSED(szString),
- time_t WXUNUSED(t)) {}
- virtual void DoLogString(const wchar_t *WXUNUSED(szString),
- time_t WXUNUSED(t)) {}
+ wxDEPRECATED_BUT_USED_INTERNALLY_INLINE(
+ virtual void DoLogString(const char *WXUNUSED(szString),
+ time_t WXUNUSED(t)),
+ )
+
+ wxDEPRECATED_BUT_USED_INTERNALLY_INLINE(
+ virtual void DoLogString(const wchar_t *WXUNUSED(wzString),
+ time_t WXUNUSED(t)),
+ )
#endif // WXWIN_COMPATIBILITY_2_8
- // this macro should be used in the derived classes to avoid warnings about
- // hiding the other DoLog() overloads when overriding DoLog(wxString) --
- // but don't use it with MSVC which doesn't give this warning but does give
- // warning when a deprecated function is overridden
-#if WXWIN_COMPATIBILITY_2_8 && !defined(__VISUALC__)
- #define wxSUPPRESS_DOLOG_HIDE_WARNING() \
- virtual void DoLog(wxLogLevel, const char *, time_t) { } \
- virtual void DoLog(wxLogLevel, const wchar_t *, time_t) { }
-
- #define wxSUPPRESS_DOLOGSTRING_HIDE_WARNING() \
- virtual void DoLogString(const char *, time_t) { } \
- virtual void DoLogString(const wchar_t *, time_t) { }
-#else
- #define wxSUPPRESS_DOLOG_HIDE_WARNING()
- #define wxSUPPRESS_DOLOGSTRING_HIDE_WARNING()
-#endif
// log a message indicating the number of times the previous message was
- // repeated if ms_prevCounter > 0, does nothing otherwise; return the old
- // value of ms_prevCounter
+ // repeated if previous repetition counter is strictly positive, does
+ // nothing otherwise; return the old value of repetition counter
unsigned LogLastRepeatIfNeeded();
private:
// implement of LogLastRepeatIfNeeded(): it assumes that the
- // caller had already locked ms_prevCS
+ // caller had already locked GetPreviousLogCS()
unsigned LogLastRepeatIfNeededUnlocked();
// static variables
// with the number of times it was repeated
static bool ms_bRepetCounting;
- static wxString ms_prevString; // previous message that was logged
- static unsigned ms_prevCounter; // how many times it was repeated
- static time_t ms_prevTimeStamp;// timestamp of the previous message
- static wxLogLevel ms_prevLevel; // level of the previous message
-
static wxLog *ms_pLogger; // currently active log sink
static bool ms_doLog; // false => all logging disabled
static bool ms_bAutoCreate; // create new log targets on demand?
virtual void Flush();
protected:
-#if wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
- virtual void DoLog(wxLogLevel level, const wxString& szString, time_t t);
-
- wxSUPPRESS_DOLOG_HIDE_WARNING()
-#endif // wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
-
- virtual void DoLogString(const wxString& szString, time_t t);
-
- wxSUPPRESS_DOLOGSTRING_HIDE_WARNING()
+ virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg);
private:
wxString m_str;
protected:
// implement sink function
- virtual void DoLogString(const wxString& szString, time_t t);
-
- wxSUPPRESS_DOLOGSTRING_HIDE_WARNING()
+ virtual void DoLogText(const wxString& msg);
FILE *m_fp;
protected:
// implement sink function
- virtual void DoLogString(const wxString& szString, time_t t);
-
- wxSUPPRESS_DOLOGSTRING_HIDE_WARNING()
+ virtual void DoLogText(const wxString& msg);
// using ptr here to avoid including <iostream.h> from this file
wxSTD ostream *m_ostr;
void DetachOldLog() { m_logOld = NULL; }
protected:
- // pass the chain to the old logger if needed
- virtual void DoLog(wxLogLevel level, const wxString& szString, time_t t);
-
- wxSUPPRESS_DOLOG_HIDE_WARNING()
+ // pass the record to the old logger if needed
+ virtual void DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info);
private:
// the current log target
/**
Different standard log levels (you may also define your own) used with
- wxLog::OnLog() by standard wxLog functions wxLogError(), wxLogWarning(),
- etc...
+ by standard wxLog functions wxLogError(), wxLogWarning(), etc...
*/
enum wxLogLevelValues
{
*/
typedef unsigned long wxLogLevel;
+/**
+ Information about a log record (unit of the log output).
+ */
+struct wxLogRecordInfo
+{
+ /// Time when the log message was generated.
+ time_t timestamp;
+
+ /**
+ Id of the thread in which the message was generated.
+
+ This field is only available if wxWidgets was built with threads
+ support (<code>wxUSE_THREADS == 1</code>).
+
+ @see wxThread::GetCurrentId()
+ */
+ wxThreadIdType threadId;
+};
/**
@class wxLogWindow
@section log_target Manipulating the log target
The functions in this section work with and manipulate the active log
- target. The OnLog() is called by the @e wxLogXXX() functions
- and invokes the DoLog() of the active log target if any.
+ target.
Get/Set methods are used to install/query the current active target and,
finally, DontCreateOnDemand() disables the automatic creation of a standard
easily lead to a loss of messages.
See also:
- @li OnLog()
@li GetActiveTarget()
@li SetActiveTarget()
@li DontCreateOnDemand()
*/
static bool IsAllowedTraceMask(const wxString& mask);
- /**
- Forwards the message at specified level to the @e DoLog() function of the
- active log target if there is any, does nothing otherwise.
- */
- static void OnLog(wxLogLevel level, const wxString& msg, time_t t);
-
/**
Remove the @a mask from the list of allowed masks for
wxLogTrace().
static void Suspend();
/**
- Log the given message.
+ Log the given record.
This function should only be called from the DoLog() implementations in
- the derived classes (which can't call wxLog::DoLog() directly as it is
- protected), it should not be used for logging new messages which can be
- only sent to the currently active logger using OnLog() which also
- checks if the logging (for this level) is enabled while this method
- just directly calls DoLog().
+ the derived classes if they need to call DoLogRecord() on another log
+ object (they can, of course, just use wxLog::DoLogRecord() call syntax
+ to call it on the object itself). It should not be used for logging new
+ messages which can be only sent to the currently active logger using
+ OnLog() which also checks if the logging (for this level) is enabled
+ while this method just directly calls DoLog().
Example of use of this class from wxLogChain:
@code
- void wxLogChain::DoLog(wxLogLevel level, const wxString& msg, time_t t)
+ void wxLogChain::DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info)
{
// let the previous logger show it
if ( m_logOld && IsPassingMessages() )
- m_logOld->Log(level, msg, t);
+ m_logOld->LogRecord(level, msg, info);
// and also send it to the new one
if ( m_logNew && m_logNew != this )
- m_logNew->Log(level, msg, t);
+ m_logNew->LogRecord(level, msg, info);
}
@endcode
- @since 2.9.0
+ @since 2.9.1
*/
- void Log(wxLogLevel level, const wxString& msg, time_t timestamp);
+ void LogRecord(wxLogLevel level, const wxString& msg, time_t timestamp);
protected:
+ /**
+ @name Logging callbacks.
+
+ The functions which should be overridden by custom log targets.
+
+ When defining a new log target, you have a choice between overriding
+ DoLogRecord(), which provides maximal flexibility, DoLogTextAtLevel()
+ which can be used if you don't intend to change the default log
+ messages formatting but want to handle log messages of different levels
+ differently or, in the simplest case, DoLogText().
+ */
+ //@{
/**
- Called to process the message of the specified severity. @a msg is the text
- of the message as specified in the call of @e wxLogXXX() function which
- generated it and @a timestamp is the moment when the message was generated.
+ Called to created log a new record.
+
+ Any log message created by wxLogXXX() functions is passed to this
+ method of the active log target. The default implementation prepends
+ the timestamp and, for some log levels (e.g. error and warning), the
+ corresponding prefix to @a msg and passes it to DoLogTextAtLevel().
- The base class version prepends the timestamp to the message, adds a prefix
- corresponding to the log level and then calls
- DoLogString() with the resulting string.
+ You may override this method to implement custom formatting of the
+ log messages or to implement custom filtering of log messages (e.g. you
+ could discard all log messages coming from the given source file).
+ */
+ virtual void DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info);
+
+ /**
+ Called to log the specified string at given level.
+
+ The base class versions logs debug and trace messages on the system
+ default debug output channel and passes all the other messages to
+ DoLogText().
*/
- virtual void DoLog(wxLogLevel level, const wxString& msg, time_t timestamp);
+ virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg);
/**
- Called to log the specified string. The timestamp is already included in the
- string but still passed to this function.
+ Called to log the specified string.
- A simple implementation may just send the string to @c stdout or, better,
- @c stderr.
+ A simple implementation might just send the string to @c stdout or
+ @c stderr or save it in a file (of course, the already existing
+ wxLogStderr can be used for this).
+
+ The base class version of this function asserts so it must be
+ overridden if you don't override DoLogRecord() or DoLogTextAtLevel().
*/
- virtual void DoLogString(const wxString& msg, time_t timestamp);
+ virtual void DoLogText(const wxString& msg);
+
+ //@}
};
static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
#endif
+// ----------------------------------------------------------------------------
+// module globals
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+// this struct is used to store information about the previous log message used
+// by OnLog() to (optionally) avoid logging multiple copies of the same message
+struct PreviousLogInfo
+{
+ PreviousLogInfo()
+ {
+ numRepeated = 0;
+ }
+
+
+ // previous message itself
+ wxString msg;
+
+ // its level
+ wxLogLevel level;
+
+ // other information about it
+ wxLogRecordInfo info;
+
+ // the number of times it was already repeated
+ unsigned numRepeated;
+};
+
+PreviousLogInfo gs_prevLog;
+
+} // anonymous namespace
+
// ============================================================================
// implementation
// ============================================================================
// generic log function
void wxVLogGeneric(wxLogLevel level, const wxString& format, va_list argptr)
{
- if ( wxLog::IsEnabled() ) {
- wxLog::OnLog(level, wxString::FormatV(format, argptr), time(NULL));
+ if ( wxLog::IsEnabled() )
+ {
+ wxLog::OnLog(level, wxString::FormatV(format, argptr));
}
}
#define IMPLEMENT_LOG_FUNCTION(level) \
void wxVLog##level(const wxString& format, va_list argptr) \
{ \
- if ( wxLog::IsEnabled() ) { \
- wxLog::OnLog(wxLOG_##level, \
- wxString::FormatV(format, argptr), time(NULL)); \
- } \
+ if ( wxLog::IsEnabled() ) \
+ wxLog::OnLog(wxLOG_##level, wxString::FormatV(format, argptr)); \
} \
IMPLEMENT_LOG_FUNCTION_WCHAR(level) \
IMPLEMENT_LOG_FUNCTION_UTF8(level)
void wxVLogVerbose(const wxString& format, va_list argptr)
{
if ( wxLog::IsEnabled() ) {
- if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() ) {
- wxLog::OnLog(wxLOG_Info,
- wxString::FormatV(format, argptr), time(NULL));
- }
+ if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() )
+ wxLog::OnLog(wxLOG_Info, wxString::FormatV(format, argptr));
}
}
{
if ( wxLog::IsEnabled() )
{
- wxLog::OnLog(wxLOG_Debug,
- wxString::FormatV(format, argptr), time(NULL));
+ wxLog::OnLog(wxLOG_Debug, wxString::FormatV(format, argptr));
}
}
wxString msg;
msg << wxS("(") << mask << wxS(") ") << wxString::FormatV(format, argptr);
- wxLog::OnLog(wxLOG_Trace, msg, time(NULL));
+ wxLog::OnLog(wxLOG_Trace, msg);
}
}
// that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
// if both bits are set.
if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) {
- wxLog::OnLog(wxLOG_Trace, wxString::FormatV(format, argptr), time(NULL));
+ wxLog::OnLog(wxLOG_Trace, wxString::FormatV(format, argptr));
}
}
void WXDLLIMPEXP_BASE wxVLogSysError(long err, const wxString& format, va_list argptr)
{
- if ( wxLog::IsEnabled() ) {
+ if ( wxLog::IsEnabled() )
+ {
wxLog::OnLog(wxLOG_Error,
- wxString::FormatV(format, argptr) + wxLogSysErrorHelper(err),
- time(NULL));
+ wxString::FormatV(format, argptr) + wxLogSysErrorHelper(err));
}
}
unsigned wxLog::LogLastRepeatIfNeededUnlocked()
{
- const unsigned count = ms_prevCounter;
+ const unsigned count = gs_prevLog.numRepeated;
- if ( ms_prevCounter )
+ if ( gs_prevLog.numRepeated )
{
wxString msg;
#if wxUSE_INTL
msg.Printf(wxPLURAL("The previous message repeated once.",
"The previous message repeated %lu times.",
- ms_prevCounter),
- ms_prevCounter);
+ gs_prevLog.numRepeated),
+ gs_prevLog.numRepeated);
#else
msg.Printf(wxS("The previous message was repeated %lu times."),
- ms_prevCounter);
+ gs_prevLog.numRepeated);
#endif
- ms_prevCounter = 0;
- ms_prevString.clear();
- DoLog(ms_prevLevel, msg, ms_prevTimeStamp);
+ gs_prevLog.numRepeated = 0;
+ gs_prevLog.msg.clear();
+ DoLogRecord(gs_prevLog.level, msg, gs_prevLog.info);
}
return count;
{
// Flush() must be called before destroying the object as otherwise some
// messages could be lost
- if ( ms_prevCounter )
+ if ( gs_prevLog.numRepeated )
{
wxMessageOutputDebug().Printf
(
wxS("Last repeated message (\"%s\", %lu times) wasn't output"),
- ms_prevString,
- ms_prevCounter
+ gs_prevLog.msg,
+ gs_prevLog.numRepeated
);
}
}
+// ----------------------------------------------------------------------------
+// wxLog logging functions
+// ----------------------------------------------------------------------------
+
+/* static */
+void
+wxLog::OnLog(wxLogLevel level, const wxString& msg, time_t t)
+{
+ wxLogRecordInfo info;
+ info.timestamp = t;
+#if wxUSE_THREADS
+ info.threadId = wxThread::GetCurrentId();
+#endif // wxUSE_THREADS
+
+ OnLog(level, msg, info);
+}
+
/* static */
-void wxLog::OnLog(wxLogLevel level, const wxString& szString, time_t t)
+void
+wxLog::OnLog(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info)
{
if ( IsEnabled() && ms_logLevel >= level )
{
{
wxCRIT_SECT_LOCKER(lock, GetPreviousLogCS());
- if ( szString == ms_prevString )
+ if ( msg == gs_prevLog.msg )
{
- ms_prevCounter++;
+ gs_prevLog.numRepeated++;
// nothing else to do, in particular, don't log the
// repeated message
pLogger->LogLastRepeatIfNeededUnlocked();
// reset repetition counter for a new message
- ms_prevString = szString;
- ms_prevLevel = level;
- ms_prevTimeStamp = t;
+ gs_prevLog.msg = msg;
+ gs_prevLog.level = level;
+ gs_prevLog.info = info;
}
- pLogger->DoLog(level, szString, t);
+ pLogger->DoLogRecord(level, msg, info);
}
}
}
-// deprecated function
-#if WXWIN_COMPATIBILITY_2_6
-
-wxChar *wxLog::SetLogBuffer(wxChar * WXUNUSED(buf), size_t WXUNUSED(size))
+void wxLog::DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info)
{
- return NULL;
+#if WXWIN_COMPATIBILITY_2_8
+ // call the old DoLog() to ensure that existing custom log classes still
+ // work
+ //
+ // as the user code could have defined it as either taking "const char *"
+ // (in ANSI build) or "const wxChar *" (in ANSI/Unicode), we have no choice
+ // but to call both of them
+ DoLog(level, (const char*)msg.mb_str(), info.timestamp);
+ DoLog(level, (const wchar_t*)msg.wc_str(), info.timestamp);
+#endif // WXWIN_COMPATIBILITY_2_8
+
+
+ // TODO: it would be better to extract message formatting in a separate
+ // wxLogFormatter class but for now we hard code formatting here
+
+ wxString prefix;
+
+ // don't time stamp debug messages under MSW as debug viewers usually
+ // already have an option to do it
+#ifdef __WXMSW__
+ if ( level != wxLOG_Debug && level != wxLOG_Trace )
+#endif // __WXMSW__
+ TimeStamp(&prefix);
+
+ // TODO: use the other wxLogRecordInfo fields
+
+ switch ( level )
+ {
+ case wxLOG_Error:
+ prefix += _("Error: ");
+ break;
+
+ case wxLOG_Warning:
+ prefix += _("Warning: ");
+ break;
+
+ // don't prepend "debug/trace" prefix under MSW as it goes to the debug
+ // window anyhow and so can't be confused with something else
+#ifndef __WXMSW__
+ case wxLOG_Debug:
+ // this prefix (as well as the one below) is intentionally not
+ // translated as nobody translates debug messages anyhow
+ prefix += "Debug: ";
+ break;
+
+ case wxLOG_Trace:
+ prefix += "Trace: ";
+ break;
+#endif // !__WXMSW__
+ }
+
+ DoLogTextAtLevel(level, prefix + msg);
}
-#endif // WXWIN_COMPATIBILITY_2_6
+void wxLog::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
+{
+ // we know about debug messages (because using wxMessageOutputDebug is the
+ // right thing to do in 99% of all cases and also for compatibility) but
+ // anything else needs to be handled in the derived class
+ if ( level == wxLOG_Debug || level == wxLOG_Trace )
+ {
+ wxMessageOutputDebug().Output(msg + wxS('\n'));
+ }
+ else
+ {
+ DoLogText(msg);
+ }
+}
-#if WXWIN_COMPATIBILITY_2_8
+void wxLog::DoLogText(const wxString& WXUNUSED(msg))
+{
+ // in 2.8-compatible build the derived class might override DoLog() or
+ // DoLogString() instead so we can't have this assert there
+#if !WXWIN_COMPATIBILITY_2_8
+ wxFAIL_MSG( "must be overridden if it is called" );
+#endif // WXWIN_COMPATIBILITY_2_8
+}
-void wxLog::DoLog(wxLogLevel WXUNUSED(level),
- const char *WXUNUSED(szString),
- time_t WXUNUSED(t))
+void wxLog::DoLog(wxLogLevel WXUNUSED(level), const char *szString, time_t t)
{
+ DoLogString(szString, t);
}
-void wxLog::DoLog(wxLogLevel WXUNUSED(level),
- const wchar_t *WXUNUSED(wzString),
- time_t WXUNUSED(t))
+void wxLog::DoLog(wxLogLevel WXUNUSED(level), const wchar_t *wzString, time_t t)
{
+ DoLogString(wzString, t);
}
-#endif // WXWIN_COMPATIBILITY_2_8
+// ----------------------------------------------------------------------------
+// wxLog active target management
+// ----------------------------------------------------------------------------
wxLog *wxLog::GetActiveTarget()
{
#endif // wxUSE_DATETIME
}
-void wxLog::DoLog(wxLogLevel level, const wxString& szString, time_t t)
-{
-#if WXWIN_COMPATIBILITY_2_8
- // DoLog() signature changed since 2.8, so we call the old versions here
- // so that existing custom log classes still work:
- DoLog(level, (const char*)szString.mb_str(), t);
- DoLog(level, (const wchar_t*)szString.wc_str(), t);
-#endif
-
- switch ( level ) {
- case wxLOG_FatalError:
- LogString(_("Fatal error: ") + szString, t);
- LogString(_("Program aborted."), t);
- Flush();
-#ifdef __WXWINCE__
- ExitThread(3);
-#else
- abort();
-#endif
- break;
-
- case wxLOG_Error:
- LogString(_("Error: ") + szString, t);
- break;
-
- case wxLOG_Warning:
- LogString(_("Warning: ") + szString, t);
- break;
-
- case wxLOG_Info:
- if ( GetVerbose() )
- case wxLOG_Message:
- case wxLOG_Status:
- default: // log unknown log levels too
- LogString(szString, t);
- break;
-
-#if wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
-#if wxUSE_LOG_TRACE
- case wxLOG_Trace:
-#endif
-#if wxUSE_LOG_DEBUG
- case wxLOG_Debug:
-#endif
- {
- wxString str;
-
- // don't prepend "debug/trace" prefix under MSW as it goes to
- // the debug window anyhow and don't add time stamp neither as
- // debug output viewers under Windows typically add it
- // themselves anyhow
- #ifndef __WXMSW__
- TimeStamp(&str);
-
- str += level == wxLOG_Trace ? wxT("Trace: ")
- : wxT("Debug: ");
- #endif // !__WXMSW__
-
- str += szString;
- wxMessageOutputDebug().Output(str);
- }
- break;
-#endif // wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
- }
-}
-
-void wxLog::DoLogString(const wxString& szString, time_t t)
-{
-#if WXWIN_COMPATIBILITY_2_8
- // DoLogString() signature changed since 2.8, so we call the old versions
- // here so that existing custom log classes still work; unfortunately this
- // also means that we can't have the wxFAIL_MSG below in compat mode
- DoLogString((const char*)szString.mb_str(), t);
- DoLogString((const wchar_t*)szString.wc_str(), t);
-#else
- wxFAIL_MSG(wxS("DoLogString must be overriden if it's called."));
- wxUnusedVar(szString);
- wxUnusedVar(t);
-#endif
-}
-
void wxLog::Flush()
{
LogLastRepeatIfNeeded();
}
}
-#if wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
-
-void wxLogBuffer::DoLog(wxLogLevel level, const wxString& szString, time_t t)
+void wxLogBuffer::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
{
// don't put debug messages in the buffer, we don't want to show
// them to the user in a msg box, log them immediately
- bool showImmediately = false;
-#if wxUSE_LOG_TRACE
- if ( level == wxLOG_Trace )
- showImmediately = true;
-#endif
-#if wxUSE_LOG_DEBUG
- if ( level == wxLOG_Debug )
- showImmediately = true;
-#endif
-
- if ( showImmediately )
+ switch ( level )
{
- wxString str;
- TimeStamp(&str);
- str += szString;
+ case wxLOG_Debug:
+ case wxLOG_Trace:
+ wxLog::DoLogTextAtLevel(level, msg);
+ break;
- wxMessageOutputDebug dbgout;
- dbgout.Printf(wxS("%s\n"), str.c_str());
- }
- else
- {
- wxLog::DoLog(level, szString, t);
+ default:
+ m_str << msg << wxS("\n");
}
}
-#endif // wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
-
-void wxLogBuffer::DoLogString(const wxString& szString, time_t WXUNUSED(t))
-{
- m_str << szString << wxS("\n");
-}
-
// ----------------------------------------------------------------------------
// wxLogStderr class implementation
// ----------------------------------------------------------------------------
m_fp = fp;
}
-void wxLogStderr::DoLogString(const wxString& szString, time_t WXUNUSED(t))
+void wxLogStderr::DoLogText(const wxString& msg)
{
- wxString str;
- TimeStamp(&str);
- str << szString;
-
- wxFputs(str, m_fp);
- wxFputc(wxS('\n'), m_fp);
+ wxFputs(msg + '\n', m_fp);
fflush(m_fp);
// under GUI systems such as Windows or Mac, programs usually don't have
wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
if ( traits && !traits->HasStderr() )
{
- wxMessageOutputDebug dbgout;
- dbgout.Printf(wxS("%s\n"), str.c_str());
+ wxMessageOutputDebug().Output(msg + wxS('\n'));
}
}
}
m_ostr = ostr;
}
-void wxLogStream::DoLogString(const wxString& szString, time_t WXUNUSED(t))
+void wxLogStream::DoLogText(const wxString& msg)
{
- wxString stamp;
- TimeStamp(&stamp);
- (*m_ostr) << stamp << szString << wxSTD endl;
+ (*m_ostr) << msg << wxSTD endl;
}
#endif // wxUSE_STD_IOSTREAM
m_logNew->Flush();
}
-void wxLogChain::DoLog(wxLogLevel level, const wxString& szString, time_t t)
+void wxLogChain::DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info)
{
// let the previous logger show it
if ( m_logOld && IsPassingMessages() )
- m_logOld->Log(level, szString, t);
+ m_logOld->LogRecord(level, msg, info);
// and also send it to the new one
if ( m_logNew && m_logNew != this )
- m_logNew->Log(level, szString, t);
+ m_logNew->LogRecord(level, msg, info);
}
#ifdef __VISUALC__
// ----------------------------------------------------------------------------
bool wxLog::ms_bRepetCounting = false;
-wxString wxLog::ms_prevString;
-unsigned int wxLog::ms_prevCounter = 0;
-time_t wxLog::ms_prevTimeStamp= 0;
-wxLogLevel wxLog::ms_prevLevel;
wxLog *wxLog::ms_pLogger = NULL;
bool wxLog::ms_doLog = true;
wxString msg;
wxLog *pLog = wxLog::GetActiveTarget();
- if ( pLog != NULL ) {
+ if ( pLog != NULL )
+ {
msg.PrintfV(format, argptr);
wxASSERT( gs_pFrame == NULL ); // should be reset!
gs_pFrame = pFrame;
-#ifdef __WXWINCE__
- wxLog::OnLog(wxLOG_Status, msg, 0);
-#else
- wxLog::OnLog(wxLOG_Status, msg, time(NULL));
-#endif
+ wxLog::OnLog(wxLOG_Status, msg);
gs_pFrame = NULL;
}
}
}
// log all kinds of messages
-void wxLogGui::DoLog(wxLogLevel level, const wxString& szString, time_t t)
+void wxLogGui::DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info)
{
- switch ( level ) {
+ switch ( level )
+ {
case wxLOG_Info:
if ( GetVerbose() )
case wxLOG_Message:
{
- m_aMessages.Add(szString);
+ m_aMessages.Add(msg);
m_aSeverity.Add(wxLOG_Message);
- m_aTimes.Add((long)t);
+ m_aTimes.Add((long)info.timestamp);
m_bHasMessages = true;
}
break;
}
if ( pFrame && pFrame->GetStatusBar() )
- pFrame->SetStatusText(szString);
+ pFrame->SetStatusText(msg);
}
#endif // wxUSE_STATUSBAR
break;
- case wxLOG_FatalError:
- // show this one immediately
- wxMessageBox(szString, _("Fatal error"), wxICON_HAND);
- wxExit();
- break;
-
case wxLOG_Error:
if ( !m_bErrors ) {
#if !wxUSE_LOG_DIALOG
m_bWarnings = true;
}
- m_aMessages.Add(szString);
+ m_aMessages.Add(msg);
m_aSeverity.Add((int)level);
- m_aTimes.Add((long)t);
+ m_aTimes.Add((long)info.timestamp);
m_bHasMessages = true;
break;
default:
// let the base class deal with debug/trace messages as well as any
// custom levels
- wxLog::DoLog(level, szString, t);
+ wxLog::DoLogRecord(level, msg, info);
}
}
// do show the message in the text control
void DoShowLogMessage(const wxString& message)
{
- m_pTextCtrl->AppendText(message);
+ m_pTextCtrl->AppendText(message + wxS('\n'));
}
wxTextCtrl *m_pTextCtrl;
m_pLogFrame->Show(bShow);
}
-void wxLogWindow::DoLog(wxLogLevel level, const wxString& szString, time_t t)
+void wxLogWindow::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
{
// first let the previous logger show it
- wxLogPassThrough::DoLog(level, szString, t);
-
- if ( m_pLogFrame ) {
- switch ( level ) {
- case wxLOG_Status:
- // by default, these messages are ignored by wxLog, so process
- // them ourselves
- if ( !szString.empty() )
- {
- wxString str;
- str << _("Status: ") << szString;
- LogString(str, t);
- }
- break;
-
- // don't put trace messages in the text window for 2 reasons:
- // 1) there are too many of them
- // 2) they may provoke other trace messages thus sending a program
- // into an infinite loop
- case wxLOG_Trace:
- break;
+ wxLogPassThrough::DoLogTextAtLevel(level, msg);
- default:
- // and this will format it nicely and call our DoLogString()
- wxLog::DoLog(level, szString, t);
- }
- }
-}
-
-void wxLogWindow::DoLogString(const wxString& szString, time_t WXUNUSED(t))
-{
- wxString msg;
+ if ( !m_pLogFrame )
+ return;
- TimeStamp(&msg);
- msg << szString << wxT('\n');
+ // don't put trace messages in the text window for 2 reasons:
+ // 1) there are too many of them
+ // 2) they may provoke other trace messages (e.g. wxMSW code uses
+ // wxLogTrace to log Windows messages and adding text to the control
+ // sends more of them) thus sending a program into an infinite loop
+ if ( level == wxLOG_Trace )
+ return;
m_pLogFrame->AddLogMessage(msg);
}
m_pTextCtrl = pTextCtrl;
}
-void wxLogTextCtrl::DoLogString(const wxString& szString, time_t WXUNUSED(t))
+void wxLogTextCtrl::DoLogText(const wxString& msg)
{
- wxString msg;
- TimeStamp(&msg);
-
- msg << szString << wxT('\n');
- m_pTextCtrl->AppendText(msg);
+ m_pTextCtrl->AppendText(msg + wxS('\n'));
}
#endif // wxUSE_LOG && wxUSE_TEXTCTRL
#include "wx/log.h"
#endif // WX_PRECOMP
+#include "wx/scopeguard.h"
+
// ----------------------------------------------------------------------------
-// test logger
+// test loggers
// ----------------------------------------------------------------------------
-// simple log sink which just stores the messages logged for each level
-class TestLog : public wxLog
+// base class for all test loggers which simply store all logged messages for
+// future examination in the test code
+class TestLogBase : public wxLog
{
public:
- TestLog() { }
+ TestLogBase() { }
wxString GetLog(wxLogLevel level) const
{
}
protected:
- virtual void DoLog(wxLogLevel level, const wxString& str, time_t WXUNUSED(t))
+ wxString m_logs[wxLOG_Trace + 1];
+
+ wxDECLARE_NO_COPY_CLASS(TestLogBase);
+};
+
+// simple log sink which just stores the messages logged for each level
+class TestLog : public TestLogBase
+{
+public:
+ TestLog() { }
+
+protected:
+ virtual void DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& WXUNUSED(info))
+ {
+ m_logs[level] = msg;
+ }
+
+private:
+ wxDECLARE_NO_COPY_CLASS(TestLog);
+};
+
+#if WXWIN_COMPATIBILITY_2_8
+
+// log sink overriding the old DoLogXXX() functions should still work too
+
+// this one overrides DoLog(char*)
+class CompatTestLog : public TestLogBase
+{
+public:
+ CompatTestLog() { }
+
+protected:
+ virtual void DoLog(wxLogLevel level, const char *str, time_t WXUNUSED(t))
{
m_logs[level] = str;
}
- wxSUPPRESS_DOLOG_HIDE_WARNING()
+ // get rid of the warning about hiding the other overload
+ virtual void DoLog(wxLogLevel WXUNUSED(level),
+ const wchar_t *WXUNUSED(str),
+ time_t WXUNUSED(t))
+ {
+ }
private:
- wxString m_logs[wxLOG_Trace + 1];
+ wxDECLARE_NO_COPY_CLASS(CompatTestLog);
+};
- wxDECLARE_NO_COPY_CLASS(TestLog);
+// and this one overload DoLogString(wchar_t*)
+class CompatTestLog2 : public wxLog
+{
+public:
+ CompatTestLog2() { }
+
+ const wxString& Get() const { return m_msg; }
+
+protected:
+ virtual void DoLogString(const wchar_t *msg, time_t WXUNUSED(t))
+ {
+ m_msg = msg;
+ }
+
+ // get rid of the warning
+ virtual void DoLogString(const char *WXUNUSED(msg), time_t WXUNUSED(t))
+ {
+ }
+
+private:
+ wxString m_msg;
+
+ wxDECLARE_NO_COPY_CLASS(CompatTestLog2);
};
+#endif // WXWIN_COMPATIBILITY_2_8
+
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
#if wxDEBUG_LEVEL
CPPUNIT_TEST( Trace );
#endif // wxDEBUG_LEVEL
+#if WXWIN_COMPATIBILITY_2_8
+ CPPUNIT_TEST( CompatLogger );
+ CPPUNIT_TEST( CompatLogger2 );
+#endif // WXWIN_COMPATIBILITY_2_8
CPPUNIT_TEST_SUITE_END();
void Functions();
#if wxDEBUG_LEVEL
void Trace();
#endif // wxDEBUG_LEVEL
+#if WXWIN_COMPATIBILITY_2_8
+ void CompatLogger();
+ void CompatLogger2();
+#endif // WXWIN_COMPATIBILITY_2_8
TestLog *m_log;
wxLog *m_logOld;
}
#endif // wxDEBUG_LEVEL
+
+#if WXWIN_COMPATIBILITY_2_8
+
+void LogTestCase::CompatLogger()
+{
+ CompatTestLog log;
+ wxLog * const logOld = wxLog::SetActiveTarget(&log);
+ wxON_BLOCK_EXIT1( wxLog::SetActiveTarget, logOld );
+
+ wxLogError("Old error");
+ CPPUNIT_ASSERT_EQUAL( "Old error", log.GetLog(wxLOG_Error) );
+}
+
+void LogTestCase::CompatLogger2()
+{
+ CompatTestLog2 log;
+ wxLog * const logOld = wxLog::SetActiveTarget(&log);
+ wxON_BLOCK_EXIT1( wxLog::SetActiveTarget, logOld );
+
+ wxLogWarning("Old warning");
+ CPPUNIT_ASSERT_EQUAL( "Old warning", log.Get() );
+}
+
+#endif // WXWIN_COMPATIBILITY_2_8