(一)
输出 log 是调试及监控程序运行状态的一种关键手段,写 GUI 程序也不例外,具体对 wxWidgets 来说,它提供了如下一系列内置函数来处理 log 的输出:
从它们的名字我们可以看出这些函数分别用于输出不同级别的 Log,而通过调用 wxLog::SetLogLevel(level) 则可以设置当前允许输出的 Log 的最高 level,比如:
wxLog::SetLogLevel(wxLOG_Debug);
通过进行这个函数调用之后,用户输出的 Log 只有级别在 wxLOG_Debug 以下才会起作用,各个log level 的大小设置如下:
enum { wxLOG_FatalError, // program can't continue, abort immediately
wxLOG_Error, // a serious error, user must be informed about it
wxLOG_Warning, // user is normally informed about it but may be ignored
wxLOG_Message, // normal message (i.e. normal output of a non GUI app)
wxLOG_Status, // informational: might go to the status line of GUI app
wxLOG_Info, // informational message (a.k.a. 'Verbose')
wxLOG_Debug, // never shown to the user, disabled in release mode
wxLOG_Trace, // trace messages are also only enabled in debug mode
wxLOG_Progress, // used for progress indicator (not yet)
wxLOG_User = 100, // user defined levels start here
wxLOG_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 供我们使用,具体下面已经列了出来:
下面是一个使用的例子:
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.