2.9.4:
------
+All:
+
+- Added wxLogFormatter to allow customizing wxLog output (Sébastien Gallou).
+
All (GUI):
- Added wxFilePickerCtrl::SetInitialDirectory().
@page overview_log wxLog Classes Overview
Classes: wxLog, wxLogStderr, wxLogStream, wxLogTextCtrl, wxLogWindow, wxLogGui, wxLogNull, wxLogBuffer,
- wxLogChain, wxLogInterposer, wxLogInterposerTemp, wxStreamToTextRedirector
+ wxLogChain, wxLogInterposer, wxLogInterposerTemp, wxStreamToTextRedirector, wxLogFormatter
Table of contents:
@li @ref overview_log_introduction
@li @ref overview_log_mt
@li @ref overview_log_customize
@li @ref overview_log_tracemasks
-@li @ref overview_log_timestamps
<hr>
level of the message. If you do want to handle messages of different levels
differently, then you should override wxLog::DoLogTextAtLevel().
-Finally, if more control over the output format is needed, then the first
-function must be overridden as it allows to construct custom messages
+Additionally, you can customize the way full log messages are constructed from
+the components (such as time stamp, source file information, logging thread ID
+and so on). This task is performed by wxLogFormatter class so you need to
+derive a custom class from it and override its Format() method to build the log
+messages in desired way. Notice that if you just need to modify (or suppress)
+the time stamp display, overriding FormatTime() is enough.
+
+Finally, if even more control over the output format is needed, then
+DoLogRecord() can be overridden as it allows to construct custom messages
depending on the log level or even do completely different things depending
on the message severity (for example, throw away all messages except
warnings and errors, show warnings on the screen and forward the error
The standard trace masks are given in wxLogTrace() documentation.
-
-@section overview_log_timestamps Timestamps
-
-The wxLog::LogRecord() function automatically prepends a time stamp
-to all the messages. The format of the time stamp may be changed: it can be
-any string with % specifications fully described in the documentation of the
-standard @e strftime() function. For example, the default format is
-@c "[%d/%b/%y %H:%M:%S] " which gives something like @c "[17/Sep/98 22:10:16] "
-(without quotes) for the current date.
-
-Setting an empty string as the time format or calling the shortcut wxLog::DisableTimestamp(),
-disables timestamping of the messages completely.
-
-@note
-Timestamping is disabled for Visual C++ users in debug builds by
-default because otherwise it would be impossible to directly go to the line
-from which the log message was generated by simply clicking in the debugger
-window on the corresponding error message. If you wish to enable it, please
-use SetTimestamp() explicitly.
-
*/
wxLogRecordInfo info;
};
+// ----------------------------------------------------------------------------
+// Derive from this class to customize format of log messages.
+// ----------------------------------------------------------------------------
+
+class WXDLLIMPEXP_BASE wxLogFormatter
+{
+public:
+ // Default constructor.
+ wxLogFormatter() { }
+
+ // Trivial but virtual destructor for the base class.
+ virtual ~wxLogFormatter() { }
+
+
+ // Override this method to implement custom formatting of the given log
+ // record. The default implementation simply prepends a level-dependent
+ // prefix to the message and optionally adds a time stamp.
+ virtual wxString Format(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info) const;
+
+protected:
+ // Override this method to change just the time stamp formatting. It is
+ // called by default Format() implementation.
+ virtual wxString FormatTime(time_t t) const;
+};
+
+
// ----------------------------------------------------------------------------
// 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
{
public:
// ctor
- wxLog() { }
+ wxLog() : m_formatter(new wxLogFormatter) { }
// make dtor virtual for all derived classes
virtual ~wxLog();
// call AddTraceMask() concurrently
static const wxArrayString& GetTraceMasks();
+ // is this trace mask in the list?
+ static bool IsAllowedTraceMask(const wxString& mask);
+
+
+ // log formatting
+ // -----------------
+
+ // Change wxLogFormatter object used by wxLog to format the log messages.
+ //
+ // wxLog takes ownership of the pointer passed in but the caller is
+ // responsible for deleting the returned pointer.
+ wxLogFormatter* SetFormatter(wxLogFormatter* formatter);
+
+
+ // All the time stamp related functions below only work when the default
+ // wxLogFormatter is being used. Defining a custom formatter overrides them
+ // as it could use its own time stamp format or format messages without
+ // using time stamp at all.
+
+
// sets the time stamp string format: this is used as strftime() format
// string for the log targets which add time stamps to the messages; set
// it to empty string to disable time stamping completely.
static void DisableTimestamp() { SetTimestamp(wxEmptyString); }
- // is this trace mask in the list?
- static bool IsAllowedTraceMask(const wxString& mask);
-
// get the current timestamp format string (maybe empty)
static const wxString& GetTimestamp() { return ms_timestamp; }
// 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)
+ // put the time stamp into the string if ms_timestamp is not empty (don't
+ // change it otherwise); the first overload uses the current time.
static void TimeStamp(wxString *str);
+ static void TimeStamp(wxString *str, time_t t);
// these methods should only be called from derived classes DoLogRecord(),
// DoLogTextAtLevel() and DoLogText() implementations respectively and
const wxLogRecordInfo& info);
+ // variables
+ // ----------------
+
+ wxLogFormatter *m_formatter; // We own this pointer.
+
+
// static variables
// ----------------
+
+/**
+ @class wxLogFormatter
+
+ wxLogFormatter class is used to format the log messages. It implements the
+ default formatting and can be derived from to create custom formatters.
+
+ The default implementation formats the message into a string containing
+ the time stamp, level-dependent prefix and the message itself.
+
+ To change it, you can derive from it and override its Format() method. For
+ example, to include the thread id in the log messages you can use
+ @code
+ class LogFormatterWithThread : public wxLogFormatter
+ {
+ virtual wxString Format(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info) const
+ {
+ return wxString::Format("[%d] %s(%d) : %s",
+ info.threadId, info.filename, info.line, msg);
+ }
+ };
+ @endcode
+ And then associate it with wxLog instance using its SetFormatter(). Then,
+ if you call:
+
+ @code
+ wxLogMessage(_("*** Application started ***"));
+ @endcode
+
+ the log output could be something like:
+
+ @verbatim
+ [7872] d:\testApp\src\testApp.cpp(85) : *** Application started ***
+ @endverbatim
+
+ @library{wxbase}
+ @category{logging}
+
+ @see @ref overview_log
+
+ @since 2.9.4
+*/
+class wxLogFormatter
+{
+public:
+ /**
+ The default ctor does nothing.
+ */
+ wxLogFormatter();
+
+
+ /**
+ This function creates the full log message string.
+
+ Override it to customize the output string format.
+
+ @param level
+ The level of this log record, e.g. ::wxLOG_Error.
+ @param msg
+ The log message itself.
+ @param info
+ All the other information (such as time, component, location...)
+ associated with this log record.
+
+ @return
+ The formated message.
+
+ @note
+ Time stamping is disabled for Visual C++ users in debug builds by
+ default because otherwise it would be impossible to directly go to the line
+ from which the log message was generated by simply clicking in the debugger
+ window on the corresponding error message. If you wish to enable it, override
+ FormatTime().
+ */
+ virtual wxString Format(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info) const;
+
+protected:
+ /**
+ This function formats the time stamp part of the log message.
+
+ Override this function if you need to customize just the time stamp.
+
+ @param time
+ Time to format.
+
+ @return
+ The formated time string, may be empty.
+ */
+ virtual wxString FormatTime(time_t time) const;
+};
+
+
/**
@class wxLog
@note For console-mode applications, the default target is wxLogStderr, so
that all @e wxLogXXX() functions print on @c stderr when @c wxUSE_GUI = 0.
- @library{wxcore}
+ @library{wxbase}
@category{logging}
@see @ref overview_log, @ref group_funcmacro_log "wxLogXXX() functions"
/**
Returns the current timestamp format string.
+
+ Notice that the current time stamp is only used by the default log
+ formatter and custom formatters may ignore this format.
*/
static const wxString& GetTimestamp();
messages. The string may contain any normal characters as well as %
prefixed format specifiers, see @e strftime() manual for details.
Passing an empty string to this function disables message time stamping.
+
+ Notice that the current time stamp is only used by the default log
+ formatter and custom formatters may ignore this format. You can also
+ define a custom wxLogFormatter to customize the time stamp handling
+ beyond changing its format.
*/
static void SetTimestamp(const wxString& format);
/**
Disables time stamping of the log messages.
+ Notice that the current time stamp is only used by the default log
+ formatter and custom formatters may ignore calls to this function.
+
@since 2.9.0
*/
static void DisableTimestamp();
//@}
+
+ /**
+ Sets the specified formatter as the active one.
+
+ @param formatter
+ The new formatter. If @NULL, reset to the default formatter.
+
+ Returns the pointer to the previous formatter. You must delete it
+ if you don't plan to attach it again to a wxLog object later.
+
+ @since 2.9.4
+ */
+ wxLogFormatter *SetFormatter(wxLogFormatter* formatter);
/**
#endif
}
+// ----------------------------------------------------------------------------
+// wxLogFormatter class implementation
+// ----------------------------------------------------------------------------
+
+wxString
+wxLogFormatter::Format(wxLogLevel level,
+ const wxString& msg,
+ const wxLogRecordInfo& info) const
+{
+ wxString prefix = FormatTime(info.timestamp);
+
+ 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__
+ }
+
+ return prefix + msg;
+}
+
+wxString
+wxLogFormatter::FormatTime(time_t t) const
+{
+ wxString str;
+
+ // 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__
+ wxLog::TimeStamp(&str, t);
+
+ return str;
+}
+
+
// ----------------------------------------------------------------------------
// wxLog class implementation
// ----------------------------------------------------------------------------
gs_prevLog.numRepeated
);
}
+
+ delete m_formatter;
}
// ----------------------------------------------------------------------------
wxUnusedVar(info);
#endif // WXWIN_COMPATIBILITY_2_8/!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);
+ // Use wxLogFormatter to format the message
+ DoLogTextAtLevel(level, m_formatter->Format (level, msg, info));
}
void wxLog::DoLogTextAtLevel(wxLogLevel level, const wxString& msg)
// wxLog miscellaneous other methods
// ----------------------------------------------------------------------------
+#if wxUSE_DATETIME
+
void wxLog::TimeStamp(wxString *str)
{
-#if wxUSE_DATETIME
if ( !ms_timestamp.empty() )
{
*str = wxDateTime::UNow().Format(ms_timestamp);
*str += wxS(": ");
}
-#endif // wxUSE_DATETIME
}
+void wxLog::TimeStamp(wxString *str, time_t t)
+{
+ if ( !ms_timestamp.empty() )
+ {
+ *str = wxDateTime(t).Format(ms_timestamp);
+ *str += wxS(": ");
+ }
+}
+
+#else // !wxUSE_DATETIME
+
+void wxLog::TimeStamp(wxString*)
+{
+}
+
+void wxLog::TimeStamp(wxString*, time_t)
+{
+}
+
+#endif // wxUSE_DATETIME/!wxUSE_DATETIME
+
#if wxUSE_THREADS
void wxLog::FlushThreadMessages()
#endif // wxUSE_THREADS
+wxLogFormatter *wxLog::SetFormatter(wxLogFormatter* formatter)
+{
+ wxLogFormatter* formatterOld = m_formatter;
+ m_formatter = formatter ? formatter : new wxLogFormatter;
+
+ return formatterOld;
+}
+
void wxLog::Flush()
{
LogLastRepeatIfNeeded();