在經過了一段漫長的歲月(其實是一直在偷懶...XD),小弟我終於把Porman-gl的log系統確定下來了,在此做些記錄。
從定義開始:
甚麼是Log system?? 定義: Log system是輔助debug的系統或工具,當Programmer在撰寫程式的過程中,希望在某些可能發生錯誤或做測試的地方,ouput出一些有義意的文字訊息到檔案或者console視窗裡,來幫助執行期間或事後追蹤使用。
實做:
通常在設計上,會對輸出的訊息做等級上的分類,一般來說,從最低到最高會分成:DEBUG、INFO、WARNING與ERROR這四種。而在DEBUG的部分又可以再以數字去分等級,例如:DEBUG1、DEBUG2、DEBUG3...etc,數字越高者代表越不重要的訊息。
為什麼要對訊息做分類?因為有時我們所log的訊息,在開發期間只是來除錯用,當程序發佈後,這些訊息就don't care了,但每當發佈版本就要Programmer把一堆開發用的訊息拿掉,是相當累人的一件事,況且你真的確定這些訊息之後就真的不需要了嗎?你敢就這樣刪除嗎?如果以後又要加回來怎麼辦呢?但不刪除,在發佈的版本中又log一堆有的沒的,耗效能不說,當出錯時,要在一堆沒用的訊息裡找到關鍵的問題所在,眼都花了,我想。
所以設計上會在log system裡加入一個等級變數,用這個等級變數來設定,哪些訊息需要被log、哪些可以被忽略不管,例如:當程序發佈時,我們通常會把等級變數設定為WARNING,這表示WARNING以上的訊息(如:INFO、DEBUG1、DEBUG2,DEBUG3...etc)不會被記錄,用這樣的方式確保當程序出錯時,不會有太多不必要的資訊混雜其中。
再來,輸出的目的地在哪?std::error、windows output還是logMsg.txt?都有可能,那就全部都做吧!其實有可以使用Observer Pattern來動態擴充,因為真的有太多可能性,與其一次想清楚,不如在class設計上預留擴充性,對吧!!
最後一個議題就是Multi-thread,一個應用程序或者lib裡通常只會有一個log system,一般來說我們也會使用Singleton pattern來限定這個系統只能有一個,但遇到需要在不同thread去log訊息時,該怎麼辦呢?沒錯就跟你想的一樣,用Mutex來解決,為每個log system裡,會寫入訊息的memeber function加入Mutex,來確保同一時間內只有一個thread會寫入訊息。
Example:
說了這麼多都沒用啦!來看code才是真的!!,以下為Porman-gl所實做的logger標頭檔:
enum LogLevel
{
LOG_ERROR,
LOG_WARNING,
LOG_INFO,
LOG_DEBUG,
LOG_DEBUG1,
LOG_DEBUG2,
LOG_DEBUG3,
LOG_DEBUG4
};
//-----------------------------
// class ILogReceiver:
//-----------------------------
class ILogReceiver
{
public:
ILogReceiver( void ) : m_bEnable(true) {}
virtual ~ILogReceiver( void ) {}
virtual bool onLog( const std::string& sLevel, const std::string& sSender,
const std::string& sMsg, int iLine ) = 0;
bool isEnable( void ) { return m_bEnable; }
void setEnable( bool bEnable ) { m_bEnable = bEnable; }
private:
bool m_bEnable;
};
//-----------------------------
// class CLogger:
//-----------------------------
class CLogger
{
public:
CLogger( void );
virtual ~CLogger( void );
void log( LogLevel level, const std::string& sSender,
const std::string& sMsg, int iLine );
void setLogLevel( LogLevel level );
LogLevel getLogLevel( void );
void registerLogReceiver( ILogReceiver* pReceiver, const std::string& sName );
bool removeLogReceiver( const std::string& sName );
bool isLogReceiverRegistered( const std::string& sName );
private:
LogLevel m_enumCurLogLevel;
std::map m_mapLogReceiver;
};
以上的說明希望對"未來的我" or "正在閱讀的你"有幫助,謝謝!!

沒有留言:
張貼留言