Really support milliseconds in wxLog

Although this was supposed to work, specifying "%l" in wxLog time stamp
format actually didn't because wxLog timestamps were stored as seconds.

Fix this by storing them as milliseconds and add a simple test (not
executed by default) showing that "%l" works correctly now.

Still keep the old wxLogRecordInfo::timestamp field for compatibility,
as it was documented.

See #13059.
This commit is contained in:
Vadim Zeitlin
2021-01-13 23:50:44 +01:00
parent 89bc7b522f
commit e6cedf6649
6 changed files with 99 additions and 11 deletions

View File

@@ -62,6 +62,7 @@ class WXDLLIMPEXP_FWD_BASE wxObject;
#include "wx/dynarray.h" #include "wx/dynarray.h"
#include "wx/hashmap.h" #include "wx/hashmap.h"
#include "wx/msgout.h" #include "wx/msgout.h"
#include "wx/time.h"
#if wxUSE_THREADS #if wxUSE_THREADS
#include "wx/thread.h" #include "wx/thread.h"
@@ -160,9 +161,11 @@ public:
// don't initialize the timestamp yet, we might not need it at all if // don't initialize the timestamp yet, we might not need it at all if
// the message doesn't end up being logged and otherwise we'll fill it // the message doesn't end up being logged and otherwise we'll fill it
// just before logging it, which won't change it by much and definitely // just before logging it, which won't change it by much
// less than a second resolution of the timestamp timestampMS = 0;
#if WXWIN_COMPATIBILITY_3_0
timestamp = 0; timestamp = 0;
#endif // WXWIN_COMPATIBILITY_3_0
#if wxUSE_THREADS #if wxUSE_THREADS
threadId = wxThread::GetCurrentId(); threadId = wxThread::GetCurrentId();
@@ -208,8 +211,13 @@ public:
// not set (i.e. wxLOG_COMPONENT not defined). It must be in ASCII. // not set (i.e. wxLOG_COMPONENT not defined). It must be in ASCII.
const char *component; const char *component;
// time of record generation // time of record generation in milliseconds since Epoch
wxLongLong_t timestampMS;
#if WXWIN_COMPATIBILITY_3_0
// preserved for compatibility only, use timestampMS instead now
time_t timestamp; time_t timestamp;
#endif // WXWIN_COMPATIBILITY_3_0
#if wxUSE_THREADS #if wxUSE_THREADS
// id of the thread which logged this record // id of the thread which logged this record
@@ -334,7 +342,12 @@ public:
protected: protected:
// Override this method to change just the time stamp formatting. It is // Override this method to change just the time stamp formatting. It is
// called by default Format() implementation. // called by default Format() implementation.
virtual wxString FormatTimeMS(wxLongLong_t msec) const;
#if WXWIN_COMPATIBILITY_3_0
// Old function which only worked at second resolution.
virtual wxString FormatTime(time_t t) const; virtual wxString FormatTime(time_t t) const;
#endif // WXWIN_COMPATIBILITY_3_0
}; };
@@ -1166,7 +1179,11 @@ private:
// As explained in wxLogRecordInfo ctor, we don't initialize its // As explained in wxLogRecordInfo ctor, we don't initialize its
// timestamp to avoid calling time() unnecessary, but now that we are // timestamp to avoid calling time() unnecessary, but now that we are
// about to log the message, we do need to do it. // about to log the message, we do need to do it.
m_info.timestamp = time(NULL); m_info.timestampMS = wxGetUTCTimeMillis().GetValue();
#if WXWIN_COMPATIBILITY_3_0
m_info.timestamp = m_info.timestampMS / 1000;
#endif // WXWIN_COMPATIBILITY_3_0
wxLog::OnLog(level, wxString::FormatV(format, argptr), m_info); wxLog::OnLog(level, wxString::FormatV(format, argptr), m_info);
} }

View File

@@ -54,7 +54,18 @@ public:
*/ */
const char *func; const char *func;
/// Time when the log message was generated. /**
Time in milliseconds since Epoch when the log message was generated.
@since 3.1.5
*/
wxLongLong_t timestampMS;
/**
Time when the log message was generated.
@deprecated Please use timestampMS instead.
*/
time_t timestamp; time_t timestamp;
/** /**
@@ -148,9 +159,30 @@ public:
const wxLogRecordInfo& info) const; const wxLogRecordInfo& info) const;
protected: protected:
/**
This function formats the time stamp part of the log message including
milliseconds.
Override this function if you need to customize just the time stamp
formatting in the log messages.
@param msec
Time to format as the number of milliseconds since
1970-01-01T00:00:00.
@return
The formatted time string, may be empty.
@since 3.1.5
*/
virtual wxString FormatTimeMS(wxLongLong_t msec) const;
/** /**
This function formats the time stamp part of the log message. This function formats the time stamp part of the log message.
@deprecated This function only exists for compatibility, please
override FormatTimeMS() in the new code.
Override this function if you need to customize just the time stamp. Override this function if you need to customize just the time stamp.
@param time @param time

View File

@@ -471,7 +471,7 @@ MyFrame::DoLogRecord(wxLogLevel level,
DoLogLine DoLogLine
( (
m_txtctrl, m_txtctrl,
wxDateTime(info.timestamp).FormatISOTime(), wxDateTime(wxLongLong(info.timestampMS)).FormatISOTime(),
info.threadId == wxThread::GetMainId() info.threadId == wxThread::GetMainId()
? wxString("main") ? wxString("main")
: wxString::Format("%lx", info.threadId), : wxString::Format("%lx", info.threadId),

View File

@@ -194,6 +194,21 @@ void wxSafeShowMessage(const wxString& title, const wxString& text)
// wxLogFormatter class implementation // wxLogFormatter class implementation
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#if WXWIN_COMPATIBILITY_3_0
// Special string used to check if FormatTime() is overridden: hopefully
// different from anything that could be reasonably returned by the overridden
// version without being as long as a GUID.
static const char* DEFAULT_FORMAT_TIME = "??";
wxString
wxLogFormatter::FormatTime(time_t WXUNUSED(t)) const
{
return wxString::FromAscii(DEFAULT_FORMAT_TIME);
}
#endif // WXWIN_COMPATIBILITY_3_0
wxString wxString
wxLogFormatter::Format(wxLogLevel level, wxLogFormatter::Format(wxLogLevel level,
const wxString& msg, const wxString& msg,
@@ -206,7 +221,15 @@ wxLogFormatter::Format(wxLogLevel level,
#ifdef __WINDOWS__ #ifdef __WINDOWS__
if ( level != wxLOG_Debug && level != wxLOG_Trace ) if ( level != wxLOG_Debug && level != wxLOG_Trace )
#endif // __WINDOWS__ #endif // __WINDOWS__
{
#if WXWIN_COMPATIBILITY_3_0
// Another backwards compatibility hack: check if FormatTime() was
// overridden in the user code.
prefix = FormatTime(info.timestamp); prefix = FormatTime(info.timestamp);
if ( prefix == DEFAULT_FORMAT_TIME )
#endif // WXWIN_COMPATIBILITY_3_0
prefix = FormatTimeMS(info.timestampMS);
}
switch ( level ) switch ( level )
{ {
@@ -237,10 +260,14 @@ wxLogFormatter::Format(wxLogLevel level,
} }
wxString wxString
wxLogFormatter::FormatTime(time_t t) const wxLogFormatter::FormatTimeMS(wxLongLong_t msec) const
{ {
wxString str; wxString str;
wxLog::TimeStamp(&str, t);
#if wxUSE_DATETIME
str = wxDateTime(wxLongLong(msec)).Format(wxLog::GetTimestamp());
str += wxS(": ");
#endif // wxUSE_DATETIME
return str; return str;
} }
@@ -321,7 +348,7 @@ void
wxLog::OnLog(wxLogLevel level, const wxString& msg, time_t t) wxLog::OnLog(wxLogLevel level, const wxString& msg, time_t t)
{ {
wxLogRecordInfo info; wxLogRecordInfo info;
info.timestamp = t; info.timestampMS = 1000*t;
#if wxUSE_THREADS #if wxUSE_THREADS
info.threadId = wxThread::GetCurrentId(); info.threadId = wxThread::GetCurrentId();
#endif // wxUSE_THREADS #endif // wxUSE_THREADS

View File

@@ -342,7 +342,7 @@ void wxLogGui::DoLogRecord(wxLogLevel level,
{ {
m_aMessages.Add(msg); m_aMessages.Add(msg);
m_aSeverity.Add(wxLOG_Message); m_aSeverity.Add(wxLOG_Message);
m_aTimes.Add((long)info.timestamp); m_aTimes.Add((long)(info.timestampMS / 1000));
m_bHasMessages = true; m_bHasMessages = true;
} }
break; break;
@@ -395,7 +395,7 @@ void wxLogGui::DoLogRecord(wxLogLevel level,
m_aMessages.Add(msg); m_aMessages.Add(msg);
m_aSeverity.Add((int)level); m_aSeverity.Add((int)level);
m_aTimes.Add((long)info.timestamp); m_aTimes.Add((long)(info.timestampMS / 1000));
m_bHasMessages = true; m_bHasMessages = true;
break; break;

View File

@@ -454,4 +454,16 @@ void macroCompilabilityTest()
wxLogDebug("hello debug %d", 42); wxLogDebug("hello debug %d", 42);
} }
// This allows to check wxLogTrace() interactively by running this test with
// WXTRACE=logtest.
TEST_CASE("wxLog::Trace", "[log][.]")
{
// Running this test without setting WXTRACE is useless.
REQUIRE( wxGetEnv("WXTRACE", NULL) );
wxLogTrace("logtest", "Starting test");
wxMilliSleep(250);
wxLogTrace("logtest", "Ending test 1/4s later");
}
#endif // wxUSE_LOG #endif // wxUSE_LOG