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

@@ -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;