(一)
输出 log 是调试及监控程序运行状态的一种关键手段,写 GUI 程序也不例外,具体对 wxWidgets 来说,它提供了如下一系列内置函数来处理 log 的输出:
- wxLogError
- wxLogWarning
- wxLogMessage
- wxLogDebug
- wxLogVerbose
从它们的名字我们可以看出这些函数分别用于输出不同级别的 Log,而通过调用 wxLog::SetLogLevel(level) 则可以设置当前允许输出的 Log 的最高 level,比如:
wxLog::SetLogLevel(wxLOG_Debug);
通过进行这个函数调用之后,用户输出的 Log 只有级别在 wxLOG_Debug 以下才会起作用,各个log level 的大小设置如下:
enum{wxLOG_FatalError, // program can't continue, abort immediatelywxLOG_Error, // a serious error, user must be informed about itwxLOG_Warning, // user is normally informed about it but may be ignoredwxLOG_Message, // normal message (i.e. normal output of a non GUI app)wxLOG_Status, // informational: might go to the status line of GUI appwxLOG_Info, // informational message (a.k.a. 'Verbose')wxLOG_Debug, // never shown to the user, disabled in release modewxLOG_Trace, // trace messages are also only enabled in debug modewxLOG_Progress, // used for progress indicator (not yet)wxLOG_User = 100, // user defined levels start herewxLOG_Max = 10000};
wxLogXXX系列函数其实都是宏,他们的声明及定义如下,声明:
DECLARE_LOG_FUNCTION(Warning);#define DECLARE_LOG_FUNCTION(level) \ extern void WXDLLIMPEXP_BASE wxLog##level(const wxChar *szFormat, \ ...)
实现:
#define IMPLEMENT_LOG_FUNCTION(level) \ void wxLog##level(const wxChar *szFormat, ...) \ { \ va_list argptr; \ va_start(argptr, szFormat); \ wxVLog##level(szFormat, argptr); \ va_end(argptr); \ }
(二)
前面简单介绍了怎样使用 wxLogXXX 来输出 log,那么这些 log 被输出到了哪里呢? 在 wx 中,log 输出的目的地,叫作 log target,可以是 file,socket,gui dialog,etc.
当然,这个 log target 也是可以设置的,比如,如果你想把所有的 log 都输出到 file,那就只需要设置一下target 为 file 则可,相应的函数如下:
wx::SetActiveTarget(wxLog* target)
需要注意的是,任何时候,Log target 只有一个,设置新的 target 则会覆盖旧的,wx 内置了一些简单常用的 Log target 供我们使用,具体下面已经列了出来:
- wxLogStderr This class logs messages to a FILE *, using stderr by default as its name suggests.
- wxLogStream This class has the same functionality as wxLogStderr, but uses ostream and cerr instead of FILE * and stderr.
- wxLogGui This is the standard log target for wxWidgets applications (it is used by default if you don't do anything) and provides the most reasonable handling of all types of messages for given platform.
- wxLogWindow This log target provides a "log console" which collects all messages generated by the application and also passes them to the previous active log target. The log window frame has a menu allowing user to clear the log, close it completely or save all messages to file.
- wxLogNull The last log class is quite particular: it doesn't do anything. The objects of this class may be instantiated to (temporarily) suppress output of wxLogXXX() functions. As an example, trying to open a non-existing file will usually provoke an error message, but if for some reasons it is unwanted, just use this construction.
下面是一个使用的例子:
wxFile file; // wxFile.Open() normally complains if file can't be opened, we don't want it { wxLogNull logNo; if ( !file.Open("bar") ) ... process error ourselves ... } // ~wxLogNull called, old log sink restored wxLogMessage("..."); // ok
如果上述内置的 log target 不满足你的要求,比如,我想把 log 输出到内存中的某个位置,这时,你需要写一个自己的log target,这个自定义的 log target 须继承自: wxLog.
class myLogTarget:public wxLog { public: myLogTarget(); virtual ~myLogTarget(); protected: //wxLogxxx virtual void DoLogString(const wxChar *szString, time_t t); virtual void DoLog(wxLogLevel level, const wxChar *szString, time_t t); };
DoLog(), DoLogString() 只需要实现一个就可以了,它们在 logging 的时候都会被调用,如:wxLogWarning(xxx),如果当前的 wxlog 的 level 允许这条 Log 输出,则最终当前 log target 的 DoLog,DoLogString 都会被调用。
这两函数只是在字符串的格式上有所不同,当你实现了自定义的 log target 后,调用 wxLog::SetActiveTarget() 设置一下,你的类就能使用了。
(三)
1)wx 在启动的时候,如果应用程序没有设置 log target,系统默认会设置一个,这个默认的设置是在第一次调用 wxLog::GetActiveTarget() 时进行的。
2)如果你不想设置自己的 log target,但又想截取一下 log message,可以用 wxLogChain 这个类来帮忙,它其实也是一个 Log target,但它比别的 log target 多做了两件事:
a) 设置自己为active target,
b) 保存一下以前的log target,这样在发生logging的时候,它会保证之前的 log target 也能接收到 log message.