一、程式日誌是商品程式中必不可少的部分。在正式商用的程式中一般對於日誌都會有一些類似的要求:
效能要求
運行時記錄層級可調整
記錄檔空間使用安全性問題
下面逐一針對上面的問題一起剖析器實現。
二、效能問題。
客戶對程式的要求當然是越高越好。如果對於日誌列印採用普通的方法,來一條日誌就寫一條日誌到檔案中,這樣效能是很低的。因為程式不斷的與磁碟進行交付,對系統的衝擊很大,有可能會影響到正常的磁碟IO請求。
對於這個問題,一般的,都是採用批量寫入的方法來解決。每寫一條日誌,並不是把日誌立即寫入檔案中,而是先寫到一個緩衝區中。當這個緩衝區達到一定的量時,再一次批量寫入到檔案中。見如下代碼實現:
if (!strLog.IsEmpty())
{
m_strWriteStrInfo += GetCurTimeStr();
// 增加記錄層級資訊
if (enLevel == ENUM_LOG_LEVEL_ERROR)
{
m_strWriteStrInfo += _T("Error! ");
}
m_strWriteStrInfo += strLog;
m_strWriteStrInfo += _T("\r\n");
}
if ( bForce
|| m_strWriteStrInfo.GetLength() > MAX_STR_LOG_INFO_LEN
|| m_iWriteBinLogLen > MAX_BIN_LOG_INFO_LEN/10)
{
// write info,達到一定量時才提交到檔案中
WriteLogToFile();
}
但這樣會帶來一個問題,如果日誌量比較少,很可能要很久才能達到批量提交的量,這樣就會造成程式寫了日誌,但是日誌寫入器還是把訊息寫在緩衝區裡,檔案中沒有及時體現出來。我們可以採用定時又定時的辦法來輸出日誌。程式對緩衝區內的日誌訊息定時強制重新整理到檔案中去。為了體現程式的使用簡單性,把這個功能放在日誌模組中實現了,從而調用日誌的程式就不用考慮定時來重新整理檔案了。見如下程式實現:
CSuperLog::CSuperLog(void)
{
// 初始化臨界區變數
InitializeCriticalSection(&m_csWriteLog);
// 啟動資訊
m_strWriteStrInfo = WELCOME_LOG_INFO;
// Create the Logger thread.
m_hThread = (HANDLE)_beginthreadex( NULL, 0, &LogProcStart, NULL, 0, &m_uiThreadID );
}
unsigned __stdcall CSuperLog::LogProcStart( void* pArguments )
{
int nCount = 1;
do
{
Sleep(300);
if (++nCount % 10 == 0 )
{
WriteLog(strTemp, ENUM_LOG_LEVEL_ERROR, true); // 每隔三秒寫一次日誌
}
} while (m_bRun);
}
采有一個全域日誌類變數,在建構函式中啟動線程,線程每隔三秒去重新整理一次檔案。