static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz);
#endif
+// ----------------------------------------------------------------------------
+// module globals
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+// this struct is used to store information about the previous log message used
+// by OnLog() to (optionally) avoid logging multiple copies of the same message
+struct PreviousLogInfo
+{
+ PreviousLogInfo()
+ {
+ numRepeated = 0;
+ }
+
+
+ // previous message itself
+ wxString msg;
+
+ // its level
+ wxLogLevel level;
+
+ // other information about it
+ wxLogRecordInfo info;
+
+ // the number of times it was already repeated
+ unsigned numRepeated;
+};
+
+PreviousLogInfo gs_prevLog;
+
+} // anonymous namespace
+
// ============================================================================
// implementation
// ============================================================================
// generic log function
void wxVLogGeneric(wxLogLevel level, const wxString& format, va_list argptr)
{
- if ( wxLog::IsEnabled() ) {
- wxLog::OnLog(level, wxString::FormatV(format, argptr), time(NULL));
+ if ( wxLog::IsEnabled() )
+ {
+ wxLog::OnLog(level, wxString::FormatV(format, argptr));
}
}
#define IMPLEMENT_LOG_FUNCTION(level) \
void wxVLog##level(const wxString& format, va_list argptr) \
{ \
- if ( wxLog::IsEnabled() ) { \
- wxLog::OnLog(wxLOG_##level, \
- wxString::FormatV(format, argptr), time(NULL)); \
- } \
+ if ( wxLog::IsEnabled() ) \
+ wxLog::OnLog(wxLOG_##level, wxString::FormatV(format, argptr)); \
} \
IMPLEMENT_LOG_FUNCTION_WCHAR(level) \
IMPLEMENT_LOG_FUNCTION_UTF8(level)
void wxVLogVerbose(const wxString& format, va_list argptr)
{
if ( wxLog::IsEnabled() ) {
- if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() ) {
- wxLog::OnLog(wxLOG_Info,
- wxString::FormatV(format, argptr), time(NULL));
- }
+ if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() )
+ wxLog::OnLog(wxLOG_Info, wxString::FormatV(format, argptr));
}
}
{
if ( wxLog::IsEnabled() )
{
- wxLog::OnLog(wxLOG_Debug,
- wxString::FormatV(format, argptr), time(NULL));
+ wxLog::OnLog(wxLOG_Debug, wxString::FormatV(format, argptr));
}
}
wxString msg;
msg << wxS("(") << mask << wxS(") ") << wxString::FormatV(format, argptr);
- wxLog::OnLog(wxLOG_Trace, msg, time(NULL));
+ wxLog::OnLog(wxLOG_Trace, msg);
}
}
// that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
// if both bits are set.
if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) {
- wxLog::OnLog(wxLOG_Trace, wxString::FormatV(format, argptr), time(NULL));
+ wxLog::OnLog(wxLOG_Trace, wxString::FormatV(format, argptr));
}
}
void WXDLLIMPEXP_BASE wxVLogSysError(long err, const wxString& format, va_list argptr)
{
- if ( wxLog::IsEnabled() ) {
+ if ( wxLog::IsEnabled() )
+ {
wxLog::OnLog(wxLOG_Error,
- wxString::FormatV(format, argptr) + wxLogSysErrorHelper(err),
- time(NULL));
+ wxString::FormatV(format, argptr) + wxLogSysErrorHelper(err));
}
}
unsigned wxLog::LogLastRepeatIfNeededUnlocked()
{
- const unsigned count = ms_prevCounter;
+ const unsigned count = gs_prevLog.numRepeated;
- if ( ms_prevCounter )
+ if ( gs_prevLog.numRepeated )
{
wxString msg;
#if wxUSE_INTL
msg.Printf(wxPLURAL("The previous message repeated once.",
"The previous message repeated %lu times.",
- ms_prevCounter),
- ms_prevCounter);
+ gs_prevLog.numRepeated),
+ gs_prevLog.numRepeated);
#else
msg.Printf(wxS("The previous message was repeated %lu times."),
- ms_prevCounter);
+ gs_prevLog.numRepeated);
#endif
- ms_prevCounter = 0;
- ms_prevString.clear();
- DoLog(ms_prevLevel, msg, ms_prevTimeStamp);
+ gs_prevLog.numRepeated = 0;
+ gs_prevLog.msg.clear();
+ DoLogRecord(gs_prevLog.level, msg, gs_prevLog.info);
}
return count;
{
// Flush() must be called before destroying the object as otherwise some
// messages could be lost
- if ( ms_prevCounter )
+ if ( gs_prevLog.numRepeated )
{
wxMessageOutputDebug().Printf
(
wxS("Last repeated message (\"%s\", %lu times) wasn't output"),
- ms_prevString,
- ms_prevCounter
+ gs_prevLog.msg,
+ gs_prevLog.numRepeated
);
}
}
+// ----------------------------------------------------------------------------
+// wxLog logging functions
+// ----------------------------------------------------------------------------
+
+/* static */
+void
+wxLog::OnLog(wxLogLevel level, const wxString& msg, time_t t)
+{
+ wxLogRecordInfo info;
+ info.timestamp = t;
+#if wxUSE_THREADS
+ info.threadId = wxThread::GetCurrentId();
+#endif // wxUSE_THREADS
+
+ OnLog(level, msg, info);
+}
+
/* static */
-void wxLog::OnLog(wxLogLevel level, const wxString& szString, time_t t)
+void
+wxLog::OnLog(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info)
{
if ( IsEnabled() && ms_logLevel >= level )
{
{
wxCRIT_SECT_LOCKER(lock, GetPreviousLogCS());
- if ( szString == ms_prevString )
+ if ( msg == gs_prevLog.msg )
{
- ms_prevCounter++;
+ gs_prevLog.numRepeated++;
// nothing else to do, in particular, don't log the
// repeated message
pLogger->LogLastRepeatIfNeededUnlocked();
// reset repetition counter for a new message
- ms_prevString = szString;
- ms_prevLevel = level;
- ms_prevTimeStamp = t;
+ gs_prevLog.msg = msg;
+ gs_prevLog.level = level;
+ gs_prevLog.info = info;
}
- pLogger->DoLog(level, szString, t);
+ pLogger->DoLogRecord(level, msg, info);
}
}
}
-// deprecated function
-#if WXWIN_COMPATIBILITY_2_6
-
-wxChar *wxLog::SetLogBuffer(wxChar * WXUNUSED(buf), size_t WXUNUSED(size))
+void wxLog::DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info)
{
- return NULL;
+#if WXWIN_COMPATIBILITY_2_8
+ // call the old DoLog() to ensure that existing custom log classes still
+ // work
+ //
+ // as the user code could have defined it as either taking "const char *"
+ // (in ANSI build) or "const wxChar *" (in ANSI/Unicode), we have no choice
+ // but to call both of them
+ DoLog(level, (const char*)msg.mb_str(), info.timestamp);
+ DoLog(level, (const wchar_t*)msg.wc_str(), info.timestamp);
+#endif // WXWIN_COMPATIBILITY_2_8
+
+
+ // TODO: it would be better to extract message formatting in a separate
+ // wxLogFormatter class but for now we hard code formatting here
+
+ wxString prefix;
+
+ // don't time stamp debug messages under MSW as debug viewers usually
+ // already have an option to do it
+#ifdef __WXMSW__
+ if ( level != wxLOG_Debug && level != wxLOG_Trace )
+#endif // __WXMSW__
+ TimeStamp(&prefix);
+
+ // TODO: use the other wxLogRecordInfo fields
+
+ switch ( level )
+ {
+ case wxLOG_Error:
+ prefix += _("Error: ");
+ break;
+
+ case wxLOG_Warning:
+ prefix += _("Warning: ");
+ break;
+
+ // don't prepend "debug/trace" prefix under MSW as it goes to the debug
+ // window anyhow and so can't be confused with something else
+#ifndef __WXMSW__
+ case wxLOG_Debug:
+ // this prefix (as well as the one below) is intentionally not
+ // translated as nobody translates debug messages anyhow
+ prefix += "Debug: ";
+ break;
+
+ case wxLOG_Trace:
+ prefix += "Trace: ";
+ break;
+#endif // !__WXMSW__
+ }
+
+ DoLogTextAtLevel(level, prefix + msg);
}
-#endif // WXWIN_COMPATIBILITY_2_6
+void wxLog::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
+{
+ // we know about debug messages (because using wxMessageOutputDebug is the
+ // right thing to do in 99% of all cases and also for compatibility) but
+ // anything else needs to be handled in the derived class
+ if ( level == wxLOG_Debug || level == wxLOG_Trace )
+ {
+ wxMessageOutputDebug().Output(msg + wxS('\n'));
+ }
+ else
+ {
+ DoLogText(msg);
+ }
+}
-#if WXWIN_COMPATIBILITY_2_8
+void wxLog::DoLogText(const wxString& WXUNUSED(msg))
+{
+ // in 2.8-compatible build the derived class might override DoLog() or
+ // DoLogString() instead so we can't have this assert there
+#if !WXWIN_COMPATIBILITY_2_8
+ wxFAIL_MSG( "must be overridden if it is called" );
+#endif // WXWIN_COMPATIBILITY_2_8
+}
-void wxLog::DoLog(wxLogLevel WXUNUSED(level),
- const char *WXUNUSED(szString),
- time_t WXUNUSED(t))
+void wxLog::DoLog(wxLogLevel WXUNUSED(level), const char *szString, time_t t)
{
+ DoLogString(szString, t);
}
-void wxLog::DoLog(wxLogLevel WXUNUSED(level),
- const wchar_t *WXUNUSED(wzString),
- time_t WXUNUSED(t))
+void wxLog::DoLog(wxLogLevel WXUNUSED(level), const wchar_t *wzString, time_t t)
{
+ DoLogString(wzString, t);
}
-#endif // WXWIN_COMPATIBILITY_2_8
+// ----------------------------------------------------------------------------
+// wxLog active target management
+// ----------------------------------------------------------------------------
wxLog *wxLog::GetActiveTarget()
{
#endif // wxUSE_DATETIME
}
-void wxLog::DoLog(wxLogLevel level, const wxString& szString, time_t t)
-{
-#if WXWIN_COMPATIBILITY_2_8
- // DoLog() signature changed since 2.8, so we call the old versions here
- // so that existing custom log classes still work:
- DoLog(level, (const char*)szString.mb_str(), t);
- DoLog(level, (const wchar_t*)szString.wc_str(), t);
-#endif
-
- switch ( level ) {
- case wxLOG_FatalError:
- LogString(_("Fatal error: ") + szString, t);
- LogString(_("Program aborted."), t);
- Flush();
-#ifdef __WXWINCE__
- ExitThread(3);
-#else
- abort();
-#endif
- break;
-
- case wxLOG_Error:
- LogString(_("Error: ") + szString, t);
- break;
-
- case wxLOG_Warning:
- LogString(_("Warning: ") + szString, t);
- break;
-
- case wxLOG_Info:
- if ( GetVerbose() )
- case wxLOG_Message:
- case wxLOG_Status:
- default: // log unknown log levels too
- LogString(szString, t);
- break;
-
-#if wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
-#if wxUSE_LOG_TRACE
- case wxLOG_Trace:
-#endif
-#if wxUSE_LOG_DEBUG
- case wxLOG_Debug:
-#endif
- {
- wxString str;
-
- // don't prepend "debug/trace" prefix under MSW as it goes to
- // the debug window anyhow and don't add time stamp neither as
- // debug output viewers under Windows typically add it
- // themselves anyhow
- #ifndef __WXMSW__
- TimeStamp(&str);
-
- str += level == wxLOG_Trace ? wxT("Trace: ")
- : wxT("Debug: ");
- #endif // !__WXMSW__
-
- str += szString;
- wxMessageOutputDebug().Output(str);
- }
- break;
-#endif // wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
- }
-}
-
-void wxLog::DoLogString(const wxString& szString, time_t t)
-{
-#if WXWIN_COMPATIBILITY_2_8
- // DoLogString() signature changed since 2.8, so we call the old versions
- // here so that existing custom log classes still work; unfortunately this
- // also means that we can't have the wxFAIL_MSG below in compat mode
- DoLogString((const char*)szString.mb_str(), t);
- DoLogString((const wchar_t*)szString.wc_str(), t);
-#else
- wxFAIL_MSG(wxS("DoLogString must be overriden if it's called."));
- wxUnusedVar(szString);
- wxUnusedVar(t);
-#endif
-}
-
void wxLog::Flush()
{
LogLastRepeatIfNeeded();
}
}
-#if wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
-
-void wxLogBuffer::DoLog(wxLogLevel level, const wxString& szString, time_t t)
+void wxLogBuffer::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
{
// don't put debug messages in the buffer, we don't want to show
// them to the user in a msg box, log them immediately
- bool showImmediately = false;
-#if wxUSE_LOG_TRACE
- if ( level == wxLOG_Trace )
- showImmediately = true;
-#endif
-#if wxUSE_LOG_DEBUG
- if ( level == wxLOG_Debug )
- showImmediately = true;
-#endif
-
- if ( showImmediately )
+ switch ( level )
{
- wxString str;
- TimeStamp(&str);
- str += szString;
+ case wxLOG_Debug:
+ case wxLOG_Trace:
+ wxLog::DoLogTextAtLevel(level, msg);
+ break;
- wxMessageOutputDebug dbgout;
- dbgout.Printf(wxS("%s\n"), str.c_str());
- }
- else
- {
- wxLog::DoLog(level, szString, t);
+ default:
+ m_str << msg << wxS("\n");
}
}
-#endif // wxUSE_LOG_DEBUG || wxUSE_LOG_TRACE
-
-void wxLogBuffer::DoLogString(const wxString& szString, time_t WXUNUSED(t))
-{
- m_str << szString << wxS("\n");
-}
-
// ----------------------------------------------------------------------------
// wxLogStderr class implementation
// ----------------------------------------------------------------------------
m_fp = fp;
}
-void wxLogStderr::DoLogString(const wxString& szString, time_t WXUNUSED(t))
+void wxLogStderr::DoLogText(const wxString& msg)
{
- wxString str;
- TimeStamp(&str);
- str << szString;
-
- wxFputs(str, m_fp);
- wxFputc(wxS('\n'), m_fp);
+ wxFputs(msg + '\n', m_fp);
fflush(m_fp);
// under GUI systems such as Windows or Mac, programs usually don't have
wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
if ( traits && !traits->HasStderr() )
{
- wxMessageOutputDebug dbgout;
- dbgout.Printf(wxS("%s\n"), str.c_str());
+ wxMessageOutputDebug().Output(msg + wxS('\n'));
}
}
}
m_ostr = ostr;
}
-void wxLogStream::DoLogString(const wxString& szString, time_t WXUNUSED(t))
+void wxLogStream::DoLogText(const wxString& msg)
{
- wxString stamp;
- TimeStamp(&stamp);
- (*m_ostr) << stamp << szString << wxSTD endl;
+ (*m_ostr) << msg << wxSTD endl;
}
#endif // wxUSE_STD_IOSTREAM
m_logNew->Flush();
}
-void wxLogChain::DoLog(wxLogLevel level, const wxString& szString, time_t t)
+void wxLogChain::DoLogRecord(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info)
{
// let the previous logger show it
if ( m_logOld && IsPassingMessages() )
- m_logOld->Log(level, szString, t);
+ m_logOld->LogRecord(level, msg, info);
// and also send it to the new one
if ( m_logNew && m_logNew != this )
- m_logNew->Log(level, szString, t);
+ m_logNew->LogRecord(level, msg, info);
}
#ifdef __VISUALC__
// ----------------------------------------------------------------------------
bool wxLog::ms_bRepetCounting = false;
-wxString wxLog::ms_prevString;
-unsigned int wxLog::ms_prevCounter = 0;
-time_t wxLog::ms_prevTimeStamp= 0;
-wxLogLevel wxLog::ms_prevLevel;
wxLog *wxLog::ms_pLogger = NULL;
bool wxLog::ms_doLog = true;