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.
- 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
-----------------------------------------------------------

View File

@ -34,9 +34,7 @@ public:
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
@ -63,9 +61,9 @@ public:
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
@ -142,11 +140,7 @@ public:
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

View File

@ -55,6 +55,10 @@ typedef unsigned long wxLogLevel;
#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
@ -116,6 +120,33 @@ enum wxLogLevelValues
#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
@ -125,7 +156,11 @@ class WXDLLIMPEXP_BASE wxLog
{
public:
// ctor
wxLog(){}
wxLog() { }
// make dtor virtual for all derived classes
virtual ~wxLog();
// these functions allow to completely disable all log messages
@ -136,10 +171,6 @@ public:
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
@ -175,7 +206,7 @@ public:
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; }
@ -234,22 +265,50 @@ public:
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
@ -257,8 +316,10 @@ public:
#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
@ -269,13 +330,34 @@ public:
#endif // WXWIN_COMPATIBILITY_2_8
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
// to the message to szString and then passes it to DoLogString()
virtual void DoLog(wxLogLevel level, const wxString& szString, time_t t);
// 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)
);
@ -283,47 +365,28 @@ protected:
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
@ -333,11 +396,6 @@ private:
// 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?
@ -378,15 +436,7 @@ public:
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;
@ -404,9 +454,7 @@ public:
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;
@ -424,9 +472,7 @@ public:
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;
@ -499,10 +545,10 @@ public:
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

View File

@ -9,8 +9,7 @@
/**
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
{
@ -35,6 +34,24 @@ 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
@ -660,8 +677,7 @@ public:
@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
@ -670,7 +686,6 @@ public:
easily lead to a loss of messages.
See also:
@li OnLog()
@li GetActiveTarget()
@li SetActiveTarget()
@li DontCreateOnDemand()
@ -767,12 +782,6 @@ public:
*/
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().
@ -854,54 +863,88 @@ public:
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.
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.
*/
virtual void DoLog(wxLogLevel level, const wxString& msg, time_t timestamp);
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().
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
string but still passed to this function.
Called to log the specified string at given level.
A simple implementation may just send the string to @c stdout or, better,
@c stderr.
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 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);
#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
// ============================================================================
@ -112,8 +146,9 @@ static inline wxCriticalSection& GetPreviousLogCS()
// 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));
}
}
@ -166,10 +201,8 @@ void wxDoLogGenericUtf8(wxLogLevel level, const char *format, ...)
#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)
@ -233,10 +266,8 @@ void wxDoLogFatalErrorUtf8(const char *format, ...)
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));
}
}
@ -269,8 +300,7 @@ void wxDoLogVerboseUtf8(const char *format, ...)
{
if ( wxLog::IsEnabled() )
{
wxLog::OnLog(wxLOG_Debug,
wxString::FormatV(format, argptr), time(NULL));
wxLog::OnLog(wxLOG_Debug, wxString::FormatV(format, argptr));
}
}
@ -302,7 +332,7 @@ void wxDoLogVerboseUtf8(const char *format, ...)
wxString msg;
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
// 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));
}
}
@ -437,10 +467,10 @@ void WXDLLIMPEXP_BASE wxDoLogSysErrorUtf8(const char *format, ...)
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));
}
}
@ -491,23 +521,23 @@ unsigned wxLog::LogLastRepeatIfNeeded()
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;
@ -517,19 +547,39 @@ wxLog::~wxLog()
{
// 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& 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 )
{
@ -540,9 +590,9 @@ void wxLog::OnLog(wxLogLevel level, const wxString& szString, time_t t)
{
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
@ -552,42 +602,112 @@ void wxLog::OnLog(wxLogLevel level, const wxString& szString, time_t t)
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;
}
#endif // WXWIN_COMPATIBILITY_2_6
#if 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 wchar_t *WXUNUSED(wzString),
time_t WXUNUSED(t))
{
}
// 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);
}
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()
{
if ( ms_bAutoCreate && ms_pLogger == NULL ) {
@ -683,87 +803,6 @@ void wxLog::TimeStamp(wxString *str)
#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();
@ -798,42 +837,20 @@ void wxLogBuffer::Flush()
}
}
#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());
default:
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;
}
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
@ -867,8 +879,7 @@ void wxLogStderr::DoLogString(const wxString& szString, time_t WXUNUSED(t))
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'));
}
}
}
@ -887,11 +898,9 @@ wxLogStream::wxLogStream(wxSTD ostream *ostr)
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
@ -933,15 +942,17 @@ void wxLogChain::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
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__
@ -981,10 +992,6 @@ wxLogInterposerTemp::wxLogInterposerTemp()
// ----------------------------------------------------------------------------
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;

View File

@ -224,16 +224,13 @@ void wxVLogStatus(wxFrame *pFrame, const wxString& format, va_list argptr)
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;
}
}
@ -403,16 +400,19 @@ void wxLogGui::Flush()
}
// 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;
@ -430,17 +430,11 @@ void wxLogGui::DoLog(wxLogLevel level, const wxString& szString, time_t t)
}
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
@ -461,16 +455,16 @@ void wxLogGui::DoLog(wxLogLevel level, const wxString& szString, time_t t)
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);
}
}
@ -523,7 +517,7 @@ private:
// 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;
@ -713,44 +707,21 @@ void wxLogWindow::Show(bool 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
wxLogPassThrough::DoLog(level, szString, t);
wxLogPassThrough::DoLogTextAtLevel(level, msg);
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;
if ( !m_pLogFrame )
return;
// 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;
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');
// 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);
}
@ -1197,13 +1168,9 @@ wxLogTextCtrl::wxLogTextCtrl(wxTextCtrl *pTextCtrl)
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

View File

@ -21,15 +21,18 @@
#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
{
@ -43,19 +46,83 @@ public:
}
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(TestLog);
wxDECLARE_NO_COPY_CLASS(CompatTestLog);
};
// 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
// ----------------------------------------------------------------------------
@ -75,6 +142,10 @@ private:
#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();
@ -82,6 +153,10 @@ private:
#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;
@ -159,3 +234,27 @@ void LogTestCase::Trace()
}
#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