Changed wxLog DoLogXXX() callbacks and introduced wxLogRecordInfo.

The main logging callback is now DoLogRecord() with DoLogTextAtLevel() and
DoLogText() provided for convenience. The old DoLog() and DoLogString() are
still called but deprecated and their overloads taking wxString which were
only added in 2.9.0 are removed.

wxLogRecordInfo allows associating more information than just the time stamp
with the log record; for now only the logging thread id was added but more
fields will make their appearance soon.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61346 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2009-07-08 13:47:33 +00:00
parent 5f7c24e2ff
commit bc73d5aec8
7 changed files with 542 additions and 381 deletions

View File

@ -129,9 +129,14 @@ Changes in behaviour not resulting in compilation errors, please read this!
manual for more details. manual for more details.
- wxTreeCtrl::GetSelection now asserts if the tree has the wxTR_MULTIPLE style. - 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. 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 Changes in behaviour which may result in compilation errors
----------------------------------------------------------- -----------------------------------------------------------

View File

@ -34,9 +34,7 @@ public:
protected: protected:
// implement sink function // implement sink function
virtual void DoLogString(const wxString& szString, time_t t); virtual void DoLogText(const wxString& msg);
wxSUPPRESS_DOLOGSTRING_HIDE_WARNING()
private: private:
// the control we use // the control we use
@ -63,9 +61,9 @@ public:
virtual void Flush(); virtual void Flush();
protected: protected:
virtual void DoLog(wxLogLevel level, const wxString& szString, time_t t); virtual void DoLogRecord(wxLogLevel level,
const wxString& msg,
wxSUPPRESS_DOLOG_HIDE_WARNING() const wxLogRecordInfo& info);
// return the title to be used for the log dialog, depending on m_bErrors // return the title to be used for the log dialog, depending on m_bErrors
// and m_bWarnings values // and m_bWarnings values
@ -142,11 +140,7 @@ public:
virtual void OnFrameDelete(wxFrame *frame); virtual void OnFrameDelete(wxFrame *frame);
protected: protected:
virtual void DoLog(wxLogLevel level, const wxString& szString, time_t t); virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg);
virtual void DoLogString(const wxString& szString, time_t t);
wxSUPPRESS_DOLOG_HIDE_WARNING()
wxSUPPRESS_DOLOGSTRING_HIDE_WARNING()
private: private:
wxLogFrame *m_pLogFrame; // the log frame wxLogFrame *m_pLogFrame; // the log frame

View File

@ -55,6 +55,10 @@ typedef unsigned long wxLogLevel;
#include "wx/dynarray.h" #include "wx/dynarray.h"
#if wxUSE_THREADS
#include "wx/thread.h"
#endif // wxUSE_THREADS
// wxUSE_LOG_DEBUG enables the debug log messages // wxUSE_LOG_DEBUG enables the debug log messages
#ifndef wxUSE_LOG_DEBUG #ifndef wxUSE_LOG_DEBUG
#if wxDEBUG_LEVEL #if wxDEBUG_LEVEL
@ -116,6 +120,33 @@ enum wxLogLevelValues
#include "wx/iosfwrap.h" #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 // 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 // normally, only a single instance of this class exists but it's not enforced
@ -125,7 +156,11 @@ class WXDLLIMPEXP_BASE wxLog
{ {
public: public:
// ctor // ctor
wxLog(){} wxLog() { }
// make dtor virtual for all derived classes
virtual ~wxLog();
// these functions allow to completely disable all log messages // these functions allow to completely disable all log messages
@ -136,10 +171,6 @@ public:
static bool EnableLogging(bool doIt = true) static bool EnableLogging(bool doIt = true)
{ bool doLogOld = ms_doLog; ms_doLog = doIt; return doLogOld; } { 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 // message buffering
// flush shows all messages if they're not logged immediately (FILE // flush shows all messages if they're not logged immediately (FILE
@ -175,7 +206,7 @@ public:
static void Resume() { ms_suspendCount--; } static void Resume() { ms_suspendCount--; }
// functions controlling the default wxLog behaviour // 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 // option
static void SetVerbose(bool bVerbose = true) { ms_bVerbose = bVerbose; } static void SetVerbose(bool bVerbose = true) { ms_bVerbose = bVerbose; }
@ -234,22 +265,50 @@ public:
static const wxString& GetTimestamp() { return ms_timestamp; } 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 // put the time stamp into the string if ms_timestamp != NULL (don't
// change it otherwise) // change it otherwise)
static void TimeStamp(wxString *str); static void TimeStamp(wxString *str);
// this method should only be called from derived classes DoLog() // these methods should only be called from derived classes DoLogRecord(),
// implementations and shouldn't be called directly, use logging functions // DoLogTextAtLevel() and DoLogText() implementations respectively and
// instead // shouldn't be called directly, use logging functions instead
void Log(wxLogLevel level, const wxString& msg, time_t t) 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 void LogTextAtLevel(wxLogLevel level, const wxString& msg)
virtual ~wxLog(); {
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 // this method exists for backwards compatibility only, don't use
@ -257,8 +316,10 @@ public:
#if WXWIN_COMPATIBILITY_2_6 #if WXWIN_COMPATIBILITY_2_6
// this function doesn't do anything any more, don't call it // this function doesn't do anything any more, don't call it
wxDEPRECATED( static wxChar *SetLogBuffer(wxChar *buf, size_t size = 0) ); wxDEPRECATED_INLINE(
#endif 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 // don't use integer masks any more, use string trace masks instead
#if WXWIN_COMPATIBILITY_2_8 #if WXWIN_COMPATIBILITY_2_8
@ -269,13 +330,34 @@ public:
#endif // WXWIN_COMPATIBILITY_2_8 #endif // WXWIN_COMPATIBILITY_2_8
protected: protected:
// the logging functions that can be overridden // 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);
// default DoLog() prepends the time stamp and a prefix corresponding // override this method to redirect output to different channels depending
// to the message to szString and then passes it to DoLogString() // on its level only; if even the level doesn't matter, override
virtual void DoLog(wxLogLevel level, const wxString& szString, time_t t); // 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 #if WXWIN_COMPATIBILITY_2_8
// these shouldn't be used by new code
wxDEPRECATED_BUT_USED_INTERNALLY( wxDEPRECATED_BUT_USED_INTERNALLY(
virtual void DoLog(wxLogLevel level, const char *szString, time_t t) virtual void DoLog(wxLogLevel level, const char *szString, time_t t)
); );
@ -283,47 +365,28 @@ protected:
wxDEPRECATED_BUT_USED_INTERNALLY( wxDEPRECATED_BUT_USED_INTERNALLY(
virtual void DoLog(wxLogLevel level, const wchar_t *wzString, time_t t) 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 // these shouldn't be used by new code
virtual void DoLogString(const char *WXUNUSED(szString), wxDEPRECATED_BUT_USED_INTERNALLY_INLINE(
time_t WXUNUSED(t)) {} virtual void DoLogString(const char *WXUNUSED(szString),
virtual void DoLogString(const wchar_t *WXUNUSED(szString), time_t WXUNUSED(t)),
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 #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 // log a message indicating the number of times the previous message was
// repeated if ms_prevCounter > 0, does nothing otherwise; return the old // repeated if previous repetition counter is strictly positive, does
// value of ms_prevCounter // nothing otherwise; return the old value of repetition counter
unsigned LogLastRepeatIfNeeded(); unsigned LogLastRepeatIfNeeded();
private: private:
// implement of LogLastRepeatIfNeeded(): it assumes that the // implement of LogLastRepeatIfNeeded(): it assumes that the
// caller had already locked ms_prevCS // caller had already locked GetPreviousLogCS()
unsigned LogLastRepeatIfNeededUnlocked(); unsigned LogLastRepeatIfNeededUnlocked();
// static variables // static variables
@ -333,11 +396,6 @@ private:
// with the number of times it was repeated // with the number of times it was repeated
static bool ms_bRepetCounting; 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 wxLog *ms_pLogger; // currently active log sink
static bool ms_doLog; // false => all logging disabled static bool ms_doLog; // false => all logging disabled
static bool ms_bAutoCreate; // create new log targets on demand? static bool ms_bAutoCreate; // create new log targets on demand?
@ -378,15 +436,7 @@ public:
virtual void Flush(); virtual void Flush();
protected: protected:
#if wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg);
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()
private: private:
wxString m_str; wxString m_str;
@ -404,9 +454,7 @@ public:
protected: protected:
// implement sink function // implement sink function
virtual void DoLogString(const wxString& szString, time_t t); virtual void DoLogText(const wxString& msg);
wxSUPPRESS_DOLOGSTRING_HIDE_WARNING()
FILE *m_fp; FILE *m_fp;
@ -424,9 +472,7 @@ public:
protected: protected:
// implement sink function // implement sink function
virtual void DoLogString(const wxString& szString, time_t t); virtual void DoLogText(const wxString& msg);
wxSUPPRESS_DOLOGSTRING_HIDE_WARNING()
// using ptr here to avoid including <iostream.h> from this file // using ptr here to avoid including <iostream.h> from this file
wxSTD ostream *m_ostr; wxSTD ostream *m_ostr;
@ -499,10 +545,10 @@ public:
void DetachOldLog() { m_logOld = NULL; } void DetachOldLog() { m_logOld = NULL; }
protected: protected:
// pass the chain to the old logger if needed // pass the record to the old logger if needed
virtual void DoLog(wxLogLevel level, const wxString& szString, time_t t); virtual void DoLogRecord(wxLogLevel level,
const wxString& msg,
wxSUPPRESS_DOLOG_HIDE_WARNING() const wxLogRecordInfo& info);
private: private:
// the current log target // the current log target

View File

@ -9,8 +9,7 @@
/** /**
Different standard log levels (you may also define your own) used with Different standard log levels (you may also define your own) used with
wxLog::OnLog() by standard wxLog functions wxLogError(), wxLogWarning(), by standard wxLog functions wxLogError(), wxLogWarning(), etc...
etc...
*/ */
enum wxLogLevelValues enum wxLogLevelValues
{ {
@ -35,6 +34,24 @@ enum wxLogLevelValues
*/ */
typedef unsigned long wxLogLevel; 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 @class wxLogWindow
@ -660,8 +677,7 @@ public:
@section log_target Manipulating the log target @section log_target Manipulating the log target
The functions in this section work with and manipulate the active log The functions in this section work with and manipulate the active log
target. The OnLog() is called by the @e wxLogXXX() functions target.
and invokes the DoLog() of the active log target if any.
Get/Set methods are used to install/query the current active target and, Get/Set methods are used to install/query the current active target and,
finally, DontCreateOnDemand() disables the automatic creation of a standard finally, DontCreateOnDemand() disables the automatic creation of a standard
@ -670,7 +686,6 @@ public:
easily lead to a loss of messages. easily lead to a loss of messages.
See also: See also:
@li OnLog()
@li GetActiveTarget() @li GetActiveTarget()
@li SetActiveTarget() @li SetActiveTarget()
@li DontCreateOnDemand() @li DontCreateOnDemand()
@ -767,12 +782,6 @@ public:
*/ */
static bool IsAllowedTraceMask(const wxString& mask); 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 Remove the @a mask from the list of allowed masks for
wxLogTrace(). wxLogTrace().
@ -854,54 +863,88 @@ public:
static void Suspend(); static void Suspend();
/** /**
Log the given message. Log the given record.
This function should only be called from the DoLog() implementations in This function should only be called from the DoLog() implementations in
the derived classes (which can't call wxLog::DoLog() directly as it is the derived classes if they need to call DoLogRecord() on another log
protected), it should not be used for logging new messages which can be object (they can, of course, just use wxLog::DoLogRecord() call syntax
only sent to the currently active logger using OnLog() which also to call it on the object itself). It should not be used for logging new
checks if the logging (for this level) is enabled while this method messages which can be only sent to the currently active logger using
just directly calls DoLog(). 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: Example of use of this class from wxLogChain:
@code @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 // let the previous logger show it
if ( m_logOld && IsPassingMessages() ) if ( m_logOld && IsPassingMessages() )
m_logOld->Log(level, msg, t); m_logOld->LogRecord(level, msg, info);
// and also send it to the new one // and also send it to the new one
if ( m_logNew && m_logNew != this ) if ( m_logNew && m_logNew != this )
m_logNew->Log(level, msg, t); m_logNew->LogRecord(level, msg, info);
} }
@endcode @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: 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 Called to created log a new record.
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.
The base class version prepends the timestamp to the message, adds a prefix Any log message created by wxLogXXX() functions is passed to this
corresponding to the log level and then calls method of the active log target. The default implementation prepends
DoLogString() with the resulting string. the timestamp and, for some log levels (e.g. error and warning), the
*/ corresponding prefix to @a msg and passes it to DoLogTextAtLevel().
virtual void DoLog(wxLogLevel level, const wxString& msg, time_t timestamp);
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. The timestamp is already included in the Called to log the specified string at given level.
string but still passed to this function.
A simple implementation may just send the string to @c stdout or, better, The base class versions logs debug and trace messages on the system
@c stderr. default debug output channel and passes all the other messages to
DoLogText().
*/ */
virtual void DoLogString(const wxString& msg, time_t timestamp); virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg);
/**
Called to log the specified string.
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 DoLogText(const wxString& msg);
//@}
}; };

View File

@ -98,6 +98,40 @@ static inline wxCriticalSection& GetPreviousLogCS()
static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz); static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
#endif #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 // implementation
// ============================================================================ // ============================================================================
@ -112,8 +146,9 @@ static inline wxCriticalSection& GetPreviousLogCS()
// generic log function // generic log function
void wxVLogGeneric(wxLogLevel level, const wxString& format, va_list argptr) void wxVLogGeneric(wxLogLevel level, const wxString& format, va_list argptr)
{ {
if ( wxLog::IsEnabled() ) { if ( wxLog::IsEnabled() )
wxLog::OnLog(level, wxString::FormatV(format, argptr), time(NULL)); {
wxLog::OnLog(level, wxString::FormatV(format, argptr));
} }
} }
@ -166,10 +201,8 @@ void wxDoLogGenericUtf8(wxLogLevel level, const char *format, ...)
#define IMPLEMENT_LOG_FUNCTION(level) \ #define IMPLEMENT_LOG_FUNCTION(level) \
void wxVLog##level(const wxString& format, va_list argptr) \ void wxVLog##level(const wxString& format, va_list argptr) \
{ \ { \
if ( wxLog::IsEnabled() ) { \ if ( wxLog::IsEnabled() ) \
wxLog::OnLog(wxLOG_##level, \ wxLog::OnLog(wxLOG_##level, wxString::FormatV(format, argptr)); \
wxString::FormatV(format, argptr), time(NULL)); \
} \
} \ } \
IMPLEMENT_LOG_FUNCTION_WCHAR(level) \ IMPLEMENT_LOG_FUNCTION_WCHAR(level) \
IMPLEMENT_LOG_FUNCTION_UTF8(level) IMPLEMENT_LOG_FUNCTION_UTF8(level)
@ -233,10 +266,8 @@ void wxDoLogFatalErrorUtf8(const char *format, ...)
void wxVLogVerbose(const wxString& format, va_list argptr) void wxVLogVerbose(const wxString& format, va_list argptr)
{ {
if ( wxLog::IsEnabled() ) { if ( wxLog::IsEnabled() ) {
if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() ) { if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() )
wxLog::OnLog(wxLOG_Info, wxLog::OnLog(wxLOG_Info, wxString::FormatV(format, argptr));
wxString::FormatV(format, argptr), time(NULL));
}
} }
} }
@ -269,8 +300,7 @@ void wxDoLogVerboseUtf8(const char *format, ...)
{ {
if ( wxLog::IsEnabled() ) if ( wxLog::IsEnabled() )
{ {
wxLog::OnLog(wxLOG_Debug, wxLog::OnLog(wxLOG_Debug, wxString::FormatV(format, argptr));
wxString::FormatV(format, argptr), time(NULL));
} }
} }
@ -302,7 +332,7 @@ void wxDoLogVerboseUtf8(const char *format, ...)
wxString msg; wxString msg;
msg << wxS("(") << mask << wxS(") ") << wxString::FormatV(format, argptr); msg << wxS("(") << mask << wxS(") ") << wxString::FormatV(format, argptr);
wxLog::OnLog(wxLOG_Trace, msg, time(NULL)); wxLog::OnLog(wxLOG_Trace, msg);
} }
} }
@ -335,7 +365,7 @@ void wxDoLogVerboseUtf8(const char *format, ...)
// that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
// if both bits are set. // if both bits are set.
if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) { 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));
} }
} }
@ -437,10 +467,10 @@ void WXDLLIMPEXP_BASE wxDoLogSysErrorUtf8(const char *format, ...)
void WXDLLIMPEXP_BASE wxVLogSysError(long err, const wxString& format, va_list argptr) void WXDLLIMPEXP_BASE wxVLogSysError(long err, const wxString& format, va_list argptr)
{ {
if ( wxLog::IsEnabled() ) { if ( wxLog::IsEnabled() )
{
wxLog::OnLog(wxLOG_Error, wxLog::OnLog(wxLOG_Error,
wxString::FormatV(format, argptr) + wxLogSysErrorHelper(err), wxString::FormatV(format, argptr) + wxLogSysErrorHelper(err));
time(NULL));
} }
} }
@ -491,23 +521,23 @@ unsigned wxLog::LogLastRepeatIfNeeded()
unsigned wxLog::LogLastRepeatIfNeededUnlocked() unsigned wxLog::LogLastRepeatIfNeededUnlocked()
{ {
const unsigned count = ms_prevCounter; const unsigned count = gs_prevLog.numRepeated;
if ( ms_prevCounter ) if ( gs_prevLog.numRepeated )
{ {
wxString msg; wxString msg;
#if wxUSE_INTL #if wxUSE_INTL
msg.Printf(wxPLURAL("The previous message repeated once.", msg.Printf(wxPLURAL("The previous message repeated once.",
"The previous message repeated %lu times.", "The previous message repeated %lu times.",
ms_prevCounter), gs_prevLog.numRepeated),
ms_prevCounter); gs_prevLog.numRepeated);
#else #else
msg.Printf(wxS("The previous message was repeated %lu times."), msg.Printf(wxS("The previous message was repeated %lu times."),
ms_prevCounter); gs_prevLog.numRepeated);
#endif #endif
ms_prevCounter = 0; gs_prevLog.numRepeated = 0;
ms_prevString.clear(); gs_prevLog.msg.clear();
DoLog(ms_prevLevel, msg, ms_prevTimeStamp); DoLogRecord(gs_prevLog.level, msg, gs_prevLog.info);
} }
return count; return count;
@ -517,19 +547,39 @@ wxLog::~wxLog()
{ {
// Flush() must be called before destroying the object as otherwise some // Flush() must be called before destroying the object as otherwise some
// messages could be lost // messages could be lost
if ( ms_prevCounter ) if ( gs_prevLog.numRepeated )
{ {
wxMessageOutputDebug().Printf wxMessageOutputDebug().Printf
( (
wxS("Last repeated message (\"%s\", %lu times) wasn't output"), wxS("Last repeated message (\"%s\", %lu times) wasn't output"),
ms_prevString, gs_prevLog.msg,
ms_prevCounter gs_prevLog.numRepeated
); );
} }
} }
// ----------------------------------------------------------------------------
// wxLog logging functions
// ----------------------------------------------------------------------------
/* static */ /* static */
void wxLog::OnLog(wxLogLevel level, const wxString& szString, time_t t) 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& msg,
const wxLogRecordInfo& info)
{ {
if ( IsEnabled() && ms_logLevel >= level ) if ( IsEnabled() && ms_logLevel >= level )
{ {
@ -540,9 +590,9 @@ void wxLog::OnLog(wxLogLevel level, const wxString& szString, time_t t)
{ {
wxCRIT_SECT_LOCKER(lock, GetPreviousLogCS()); 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 // nothing else to do, in particular, don't log the
// repeated message // repeated message
@ -552,42 +602,112 @@ void wxLog::OnLog(wxLogLevel level, const wxString& szString, time_t t)
pLogger->LogLastRepeatIfNeededUnlocked(); pLogger->LogLastRepeatIfNeededUnlocked();
// reset repetition counter for a new message // reset repetition counter for a new message
ms_prevString = szString; gs_prevLog.msg = msg;
ms_prevLevel = level; gs_prevLog.level = level;
ms_prevTimeStamp = t; gs_prevLog.info = info;
} }
pLogger->DoLog(level, szString, t); pLogger->DoLogRecord(level, msg, info);
} }
} }
} }
// deprecated function void wxLog::DoLogRecord(wxLogLevel level,
#if WXWIN_COMPATIBILITY_2_6 const wxString& msg,
const wxLogRecordInfo& info)
wxChar *wxLog::SetLogBuffer(wxChar * WXUNUSED(buf), size_t WXUNUSED(size))
{ {
return NULL;
}
#endif // WXWIN_COMPATIBILITY_2_6
#if WXWIN_COMPATIBILITY_2_8 #if WXWIN_COMPATIBILITY_2_8
// call the old DoLog() to ensure that existing custom log classes still
void wxLog::DoLog(wxLogLevel WXUNUSED(level), // work
const char *WXUNUSED(szString), //
time_t WXUNUSED(t)) // 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);
void wxLog::DoLog(wxLogLevel WXUNUSED(level), DoLog(level, (const wchar_t*)msg.wc_str(), info.timestamp);
const wchar_t *WXUNUSED(wzString),
time_t WXUNUSED(t))
{
}
#endif // WXWIN_COMPATIBILITY_2_8 #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);
}
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);
}
}
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 *szString, time_t t)
{
DoLogString(szString, t);
}
void wxLog::DoLog(wxLogLevel WXUNUSED(level), const wchar_t *wzString, time_t t)
{
DoLogString(wzString, t);
}
// ----------------------------------------------------------------------------
// wxLog active target management
// ----------------------------------------------------------------------------
wxLog *wxLog::GetActiveTarget() wxLog *wxLog::GetActiveTarget()
{ {
if ( ms_bAutoCreate && ms_pLogger == NULL ) { if ( ms_bAutoCreate && ms_pLogger == NULL ) {
@ -683,87 +803,6 @@ void wxLog::TimeStamp(wxString *str)
#endif // wxUSE_DATETIME #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() void wxLog::Flush()
{ {
LogLastRepeatIfNeeded(); LogLastRepeatIfNeeded();
@ -798,42 +837,20 @@ void wxLogBuffer::Flush()
} }
} }
#if wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE void wxLogBuffer::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
void wxLogBuffer::DoLog(wxLogLevel level, const wxString& szString, time_t t)
{ {
// don't put debug messages in the buffer, we don't want to show // 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 // them to the user in a msg box, log them immediately
bool showImmediately = false; switch ( level )
#if wxUSE_LOG_TRACE
if ( level == wxLOG_Trace )
showImmediately = true;
#endif
#if wxUSE_LOG_DEBUG
if ( level == wxLOG_Debug )
showImmediately = true;
#endif
if ( showImmediately )
{ {
wxString str; case wxLOG_Debug:
TimeStamp(&str); case wxLOG_Trace:
str += szString; wxLog::DoLogTextAtLevel(level, msg);
break;
wxMessageOutputDebug dbgout; default:
dbgout.Printf(wxS("%s\n"), str.c_str()); m_str << msg << wxS("\n");
} }
else
{
wxLog::DoLog(level, szString, t);
}
}
#endif // wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
void wxLogBuffer::DoLogString(const wxString& szString, time_t WXUNUSED(t))
{
m_str << szString << wxS("\n");
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -848,14 +865,9 @@ wxLogStderr::wxLogStderr(FILE *fp)
m_fp = fp; m_fp = fp;
} }
void wxLogStderr::DoLogString(const wxString& szString, time_t WXUNUSED(t)) void wxLogStderr::DoLogText(const wxString& msg)
{ {
wxString str; wxFputs(msg + '\n', m_fp);
TimeStamp(&str);
str << szString;
wxFputs(str, m_fp);
wxFputc(wxS('\n'), m_fp);
fflush(m_fp); fflush(m_fp);
// under GUI systems such as Windows or Mac, programs usually don't have // under GUI systems such as Windows or Mac, programs usually don't have
@ -867,8 +879,7 @@ void wxLogStderr::DoLogString(const wxString& szString, time_t WXUNUSED(t))
wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
if ( traits && !traits->HasStderr() ) if ( traits && !traits->HasStderr() )
{ {
wxMessageOutputDebug dbgout; wxMessageOutputDebug().Output(msg + wxS('\n'));
dbgout.Printf(wxS("%s\n"), str.c_str());
} }
} }
} }
@ -887,11 +898,9 @@ wxLogStream::wxLogStream(wxSTD ostream *ostr)
m_ostr = ostr; m_ostr = ostr;
} }
void wxLogStream::DoLogString(const wxString& szString, time_t WXUNUSED(t)) void wxLogStream::DoLogText(const wxString& msg)
{ {
wxString stamp; (*m_ostr) << msg << wxSTD endl;
TimeStamp(&stamp);
(*m_ostr) << stamp << szString << wxSTD endl;
} }
#endif // wxUSE_STD_IOSTREAM #endif // wxUSE_STD_IOSTREAM
@ -933,15 +942,17 @@ void wxLogChain::Flush()
m_logNew->Flush(); 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 // let the previous logger show it
if ( m_logOld && IsPassingMessages() ) if ( m_logOld && IsPassingMessages() )
m_logOld->Log(level, szString, t); m_logOld->LogRecord(level, msg, info);
// and also send it to the new one // and also send it to the new one
if ( m_logNew && m_logNew != this ) if ( m_logNew && m_logNew != this )
m_logNew->Log(level, szString, t); m_logNew->LogRecord(level, msg, info);
} }
#ifdef __VISUALC__ #ifdef __VISUALC__
@ -981,10 +992,6 @@ wxLogInterposerTemp::wxLogInterposerTemp()
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
bool wxLog::ms_bRepetCounting = false; 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; wxLog *wxLog::ms_pLogger = NULL;
bool wxLog::ms_doLog = true; bool wxLog::ms_doLog = true;

View File

@ -224,16 +224,13 @@ void wxVLogStatus(wxFrame *pFrame, const wxString& format, va_list argptr)
wxString msg; wxString msg;
wxLog *pLog = wxLog::GetActiveTarget(); wxLog *pLog = wxLog::GetActiveTarget();
if ( pLog != NULL ) { if ( pLog != NULL )
{
msg.PrintfV(format, argptr); msg.PrintfV(format, argptr);
wxASSERT( gs_pFrame == NULL ); // should be reset! wxASSERT( gs_pFrame == NULL ); // should be reset!
gs_pFrame = pFrame; gs_pFrame = pFrame;
#ifdef __WXWINCE__ wxLog::OnLog(wxLOG_Status, msg);
wxLog::OnLog(wxLOG_Status, msg, 0);
#else
wxLog::OnLog(wxLOG_Status, msg, time(NULL));
#endif
gs_pFrame = NULL; gs_pFrame = NULL;
} }
} }
@ -403,16 +400,19 @@ void wxLogGui::Flush()
} }
// log all kinds of messages // 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: case wxLOG_Info:
if ( GetVerbose() ) if ( GetVerbose() )
case wxLOG_Message: case wxLOG_Message:
{ {
m_aMessages.Add(szString); m_aMessages.Add(msg);
m_aSeverity.Add(wxLOG_Message); m_aSeverity.Add(wxLOG_Message);
m_aTimes.Add((long)t); m_aTimes.Add((long)info.timestamp);
m_bHasMessages = true; m_bHasMessages = true;
} }
break; break;
@ -430,17 +430,11 @@ void wxLogGui::DoLog(wxLogLevel level, const wxString& szString, time_t t)
} }
if ( pFrame && pFrame->GetStatusBar() ) if ( pFrame && pFrame->GetStatusBar() )
pFrame->SetStatusText(szString); pFrame->SetStatusText(msg);
} }
#endif // wxUSE_STATUSBAR #endif // wxUSE_STATUSBAR
break; break;
case wxLOG_FatalError:
// show this one immediately
wxMessageBox(szString, _("Fatal error"), wxICON_HAND);
wxExit();
break;
case wxLOG_Error: case wxLOG_Error:
if ( !m_bErrors ) { if ( !m_bErrors ) {
#if !wxUSE_LOG_DIALOG #if !wxUSE_LOG_DIALOG
@ -461,16 +455,16 @@ void wxLogGui::DoLog(wxLogLevel level, const wxString& szString, time_t t)
m_bWarnings = true; m_bWarnings = true;
} }
m_aMessages.Add(szString); m_aMessages.Add(msg);
m_aSeverity.Add((int)level); m_aSeverity.Add((int)level);
m_aTimes.Add((long)t); m_aTimes.Add((long)info.timestamp);
m_bHasMessages = true; m_bHasMessages = true;
break; break;
default: default:
// let the base class deal with debug/trace messages as well as any // let the base class deal with debug/trace messages as well as any
// custom levels // custom levels
wxLog::DoLog(level, szString, t); wxLog::DoLogRecord(level, msg, info);
} }
} }
@ -523,7 +517,7 @@ private:
// do show the message in the text control // do show the message in the text control
void DoShowLogMessage(const wxString& message) void DoShowLogMessage(const wxString& message)
{ {
m_pTextCtrl->AppendText(message); m_pTextCtrl->AppendText(message + wxS('\n'));
} }
wxTextCtrl *m_pTextCtrl; wxTextCtrl *m_pTextCtrl;
@ -713,44 +707,21 @@ void wxLogWindow::Show(bool bShow)
m_pLogFrame->Show(bShow); 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 // first let the previous logger show it
wxLogPassThrough::DoLog(level, szString, t); wxLogPassThrough::DoLogTextAtLevel(level, msg);
if ( m_pLogFrame ) { if ( !m_pLogFrame )
switch ( level ) { return;
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: // don't put trace messages in the text window for 2 reasons:
// 1) there are too many of them // 1) there are too many of them
// 2) they may provoke other trace messages thus sending a program // 2) they may provoke other trace messages (e.g. wxMSW code uses
// into an infinite loop // wxLogTrace to log Windows messages and adding text to the control
case wxLOG_Trace: // sends more of them) thus sending a program into an infinite loop
break; if ( level == wxLOG_Trace )
return;
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;
TimeStamp(&msg);
msg << szString << wxT('\n');
m_pLogFrame->AddLogMessage(msg); m_pLogFrame->AddLogMessage(msg);
} }
@ -1197,13 +1168,9 @@ wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl)
m_pTextCtrl = pTextCtrl; m_pTextCtrl = pTextCtrl;
} }
void wxLogTextCtrl::DoLogString(const wxString& szString, time_t WXUNUSED(t)) void wxLogTextCtrl::DoLogText(const wxString& msg)
{ {
wxString msg; m_pTextCtrl->AppendText(msg + wxS('\n'));
TimeStamp(&msg);
msg << szString << wxT('\n');
m_pTextCtrl->AppendText(msg);
} }
#endif // wxUSE_LOG && wxUSE_TEXTCTRL #endif // wxUSE_LOG && wxUSE_TEXTCTRL

View File

@ -21,15 +21,18 @@
#include "wx/log.h" #include "wx/log.h"
#endif // WX_PRECOMP #endif // WX_PRECOMP
#include "wx/scopeguard.h"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// test logger // test loggers
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// simple log sink which just stores the messages logged for each level // base class for all test loggers which simply store all logged messages for
class TestLog : public wxLog // future examination in the test code
class TestLogBase : public wxLog
{ {
public: public:
TestLog() { } TestLogBase() { }
wxString GetLog(wxLogLevel level) const wxString GetLog(wxLogLevel level) const
{ {
@ -43,19 +46,83 @@ public:
} }
protected: 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; 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: 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 // test class
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -75,6 +142,10 @@ private:
#if wxDEBUG_LEVEL #if wxDEBUG_LEVEL
CPPUNIT_TEST( Trace ); CPPUNIT_TEST( Trace );
#endif // wxDEBUG_LEVEL #endif // wxDEBUG_LEVEL
#if WXWIN_COMPATIBILITY_2_8
CPPUNIT_TEST( CompatLogger );
CPPUNIT_TEST( CompatLogger2 );
#endif // WXWIN_COMPATIBILITY_2_8
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
void Functions(); void Functions();
@ -82,6 +153,10 @@ private:
#if wxDEBUG_LEVEL #if wxDEBUG_LEVEL
void Trace(); void Trace();
#endif // wxDEBUG_LEVEL #endif // wxDEBUG_LEVEL
#if WXWIN_COMPATIBILITY_2_8
void CompatLogger();
void CompatLogger2();
#endif // WXWIN_COMPATIBILITY_2_8
TestLog *m_log; TestLog *m_log;
wxLog *m_logOld; wxLog *m_logOld;
@ -159,3 +234,27 @@ void LogTestCase::Trace()
} }
#endif // wxDEBUG_LEVEL #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