wxwidgets 日誌類

概述

wxWidgets中提供了基本的日誌記錄功能wxLog類,該類定義了日誌目標的標準接口以及該接口的幾種標準實現以及與之配合使用的一系列功能。

wxLogXXX() 函數。它們都具有與printf() 或vprintf() 相同的語法,即它們將格式字符串作爲第一個參數,並分別使用可變數量的參數或可變參數列表指針。這些都是:

  • wxLogMessage:  適用於所有普通的參考消息。默認情況下,它們還會顯示在消息框中
  • wxLogInfo
  • wxLogWarning: 發出警告,  它們通常也會顯示給用戶,但不要中斷程序的工作。
  • wxLogError: 是用於錯誤消息(即必須顯示給用戶的消息)的函數。默認處理是彈出一個消息框,以通知用戶有關此消息的信息。
  • wxLogDebug:  是調試輸出函數。 它僅在調試模式下(定義了預處理器符號WXDEBUG時)才執行任何操作,而在正式模式下則爲無。
  • wxLogVerbose: 用於詳細輸出。通常,它是隱藏的,但如果用戶希望瞭解有關程序進度的更多詳細信息,則可以激活它
  • wxLogStatus:  用於狀態消息。它們將進入活動的或指定的(作爲第一個參數)wxFrame(如果有)的狀態欄中。

這幾個Log函數分別處在不同的等級(level),通過調用wxLog::SetLogLevel(level)可以設置當前允許輸出的最高level.

默認情況下,大多數日誌消息都是啓用的。這意味着將處理wxWidgets代碼本身日誌的錯誤(例如wxFile::Open()在無法打開文件時記錄錯誤),並顯示給用戶。要完全禁用日誌記錄,可以使用wxLog::EnableLogging()方法,或更常見的是使用wxLogNull類,該類會暫時禁用日誌記錄,並在銷燬日誌時將其恢復爲原始設置。

如果僅記錄重要消息中,可以通過wxLog::SetLogLevel()設置日誌級別 ,  例如wxLOG_Warning值–這將完全禁用嚴重性小於警告的所有日誌記錄消息,因此將不再向用戶顯示wxLogMessage()輸出。 此外,可以爲不同的日誌組件分別設置日誌級別。

日誌目標

wxWidgets具有日誌目標的概念:它只是從wxLog派生的類。這樣,它實現了基類的虛函數,在記錄消息時會調用這些虛函數。任何時候只有一個日誌目標處於活動狀態,這是wxLogXXX()函數使用的目標。日誌對象(即從wxLog派生的類的對象)的正常用法是通過調用SetActiveTarget()將其安裝爲活動目標,並且隨後對wxLogXXX()函數的所有調用都會自動使用它。

要創建一個新的日誌目標類,您只需要從wxLog派生它,並覆蓋其中的wxLog::DoLogRecord(),wxLog::DoLogTextAtLevel()和wxLog::DoLogText()中的一個或幾個即可。第一個是最靈活的,它允許您更改消息的格式,動態過濾和重定向它們等等, 所有日誌消息(由wxLogFatalError()生成的消息除外)均通過此函數傳遞。如果您只是想將日誌消息重定向到其他地方而不更改其格式,則應重寫wxLog::DoLogTextAtLevel()。最後,如果您只想重定向日誌消息,而目標不取決於消息日誌級別,則只需重寫wxLog::DoLogText()就足夠了。

wxLog派生了一些預定義的類,這些類可能有助於瞭解如何創建新的日誌目標類,當然,無需進行任何更改就可以使用它們

wxLogStderr:此類將消息記錄到FILE *,默認情況下使用stderr作爲名稱。

wxLogStream:此類具有與wxLogStderr相同的功能,但是使用ostream和cerr而不是FILE *和stderr。

wxLogGui:這是wxWidgets應用程序的標準日誌目標(如果您不執行任何操作,默認情況下會使用它),並且爲給定平臺提供對所有類型消息的最合理處理。

wxLogWindow:此日誌目標提供一個“日誌控制檯”,該控制檯收集由應用程序生成的所有消息,並將它們傳遞給先前的活動日誌目標。日誌窗口框架有一個菜單,允許用戶清除日誌,完全關閉日誌或將所有消息保存到文件中。

wxLogBuffer:此目標將所有記錄的消息收集在一個內部緩衝區中,以便稍後將其全部顯示給用戶。

wxLogNull:最後一個日誌類非常特殊:它什麼也不做。可以實例化此類的對象以(臨時)禁止wxLogXXX() 函數的輸出。例如,嘗試打開不存在的文件通常會引發錯誤消息,但是如果由於某些原因它是不需要的,則使用以下結構

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

日誌定製

要更改日誌記錄行爲,可以自定義一個日誌類。

定義一個繼承自wxLog的類,該類在主應用程序窗口的某些部分顯示所有日誌消息,這些消息保留用於消息輸出,而且模式消息框不會中斷用戶工作流程。

要自定義日誌類,可以調用wxLog::SetActiveTarget() 或 創建wxAppTraits派生的類並覆蓋其中wxAppTraits::CreateLogTarget() 虛擬方法,也可以將wxApp::CreateTraits() 覆蓋爲返回自定義日誌對象的實例。

請注意,在後一種情況下,應該在程序開始期間以及程序關閉期間啓動記錄日誌消息,因此不應該依賴主應用程序窗口的存在, 當用作wxWidgets的日誌對象自動切換爲使用wxLogStderr時,可以假設GUI(已經/仍然)可用。

在派生類中通過重寫三個方法,以自定義日誌消息處理:wxLog::DoLogRecord(),wxLog::DoLogTextAtLevel()和wxLog::DoLogText()。

如果需要對輸出格式進行更多控制,則可以重寫wxLog::DoLogRecord(),因爲它允許根據日誌級別構造自定義消息,甚至可以根據消息嚴重性來做完全不同的事情;

如果需要以不同的方式處理不同級別的消息,則應重寫wxLog::DoLogTextAtLevel();

如果只是想將日誌輸出重定向到其他位置,而不考慮消息的級別,則重寫wxLog::DoLogText()。

如果需要構造完整日誌消息的方式(例如時間戳,源文件信息,日誌記錄線程ID等),需要從該類派生一個自定義類,並重寫其Format()方法以按期望的方式構建日誌消息, 如果只需要修改(或取消顯示)時間戳顯示,則覆蓋FormatTime()就足夠了。

日誌類事例:

/*  mylog.h   */
#ifndef MYLOG_H
#define MYLOG_H

class MyLog : public wxLog
{
public:
    /************************************************************************/
    /*
    MyLog 構造函數構造一個日誌信息對象
    參數信息:
    tofile	: bool類型,爲true信息將被保存到文件,爲0將以window的形式顯示信息,默認爲true
    filename    : 打印到文件名字,只有tofile爲true方見效,如果tofile爲false傳遞wxEmptyString,默認爲mylog.log
    */
    /************************************************************************/
    MyLog(bool tofile = true, wxString filename = wxT("mylog.log"));
    ~MyLog();

private:
    FILE* m_logFile;
    void DoLogText(const wxString& msg) {};
};

#endif // MYLOG_H


/* mylog.cpp */
#include "MyLog.h"

#include "wx/log.h"
#include "wx/stdpaths.h"
#include "wx/file.h"
#include "wx/filename.h"

MyLog::MyLog(bool tofile, wxString filename)
    :m_logFile(NULL)
{
    wxLog::SetTimestamp(wxT("%Y-%m-%d %H:%M:%S"));
    wxLog::SetLogLevel(wxLOG_Debug);

    if(tofile)
    {
	wxString apppath;
        wxStandardPathsBase& stpd = wxStandardPaths::Get();
        wxFileName exeFile(stpd.GetExecutablePath());
        apppath = exeFile.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR);

        wxString file_path = apppath + filename;
        wxCharBuffer bf = file_path.ToUTF8();
        const char* c_filepath = bf.data();
        char* file_mode = "a+";
        if((m_logFile = fopen(c_filepath, file_mode)) == NULL)
        {
            wxLogError(wxT("Open file failed!"));
        }
        delete wxLog::SetActiveTarget(new wxLogStderr(m_logFile));
    } else {
	wxString LogTitle(wxT("Log Window"));
	wxLogWindow *log_window_m = new wxLogWindow(NULL, LogTitle, false, false);
	log_window_m->SetVerbose(true);
	log_window_m->Show(true);
    }
}

MyLog::~MyLog()
{
    if(m_logFile != NULL)
        fclose(m_logFile);
}

使用

/*   MyApp.h   */
#include <wx/app.h>
#include "MyLog.h"

class MyApp : public wxApp
{
    public:
        virtual bool OnInit();
        virtual int OnExit();        

        MyLog *mylog;
        ...
};


/*   MyApp.cpp   */
IMPLEMENT_APP(MyApp);   // 創建MyApp類的實例

bool MyApp::OnInit()
{
    mylog = new MyLog(true, wxT("my.log"));
    wxLogInfo("start myapp");
    ...
}

int MyApp::OnExit()
{
    if ( mylog != NULL )
    {
        delete mylog;
    }
}


/*  MyFrame.cpp */
void MyFrame::OnAbout(wxCommandEvent &event)
{
    wxString msg = wxString::Format(wxT("%s(%d: %s):%s"),__TFILE__, __LINE__, __FUNCTION__, wxT("about app"));
    wxLogInfo(msg);
    wxMessageBox(wxT("about"), wxT("Welcome to..."));
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章