來自mooon的最簡單的日誌類CSimpleLogger
來源:互聯網
上載者:User
/** *
單個標頭檔,可即時獨立使用
,只要定義了宏NOT_WITH_MOOON,即不依賴於mooon * 簡單的寫日誌類,非安全執行緒,提供按大小滾動功能 * 不追求功能,也不追求效能,只求簡單,若要功能強、效能高,可以使用CLogger * * 使用方法: * 1) 構造一個
CSimpleLogger對象 *
CSimpleLogger
logger(".", "test.log", 1024*1024, 10); * 2) 調用print方法寫日誌 * logger.
print("%s\n", "test"); */#ifndef MOOON_SYS_SIMPLE_LOGGER_H#define MOOON_SYS_SIMPLE_LOGGER_H// 只要定義了NOT_WITH_MOOON宏,// 則本檔案和mooon無任何關係,方便整合到自己的代碼中
#define NOT_WITH_MOOON#if !defined(NOT_WITH_MOOON)#include <sys/config.h>#endif // NOT_WITH_MOOON#include <stdio.h>#include <stdarg.h>#include <time.h>#include <sstream>#if !defined(NOT_WITH_MOOON)SYS_NAMESPACE_BEGIN#endif // NOT_WITH_MOOON/*** * 萬能型類型轉換函式 */template <typename AnyType>inline std::string any2string(AnyType any_value){ std::stringstream result_stream; result_stream << any_value; return result_stream.str();}/*** * 取目前時間,和date_util.h有重複,但為保持simple_logger.h的獨立性,在所難免 */inline void get_current_datetime(char* datetime_buffer, size_t datetime_buffer_size){ struct tm result; time_t now = time(NULL); localtime_r(&now, &result); snprintf(datetime_buffer, datetime_buffer_size ,"%04d-%02d-%02d %02d:%02d:%02d" ,result.tm_year+1900, result.tm_mon+1, result.tm_mday ,result.tm_hour, result.tm_min, result.tm_sec);}class
CSimpleLogger{public: /*** * 構造一個CSimpleLogger,並建立或開啟記錄檔 * @log_dir 日誌存放的目錄,不需要以斜杠結尾,目錄必須已經存在 * @filename 日誌的檔案名稱,不包含目錄部分, * 由log_dir和filename共同組成記錄檔路徑 * @log_size 每個記錄檔的大小,單位為位元組數,如果小於1024,則會被強製為1024 * @log_numer 日誌滾動的個數 * @record_size 單條日誌的大小,超過會被截斷,單位為位元組數,如果小於1024,則會被強製為1024 */
CSimpleLogger(const std::string& log_dir ,const std::string& filename ,unsigned int log_size = 1024*1024*100 ,unsigned char log_numer = 10 ,unsigned short record_size = 8192); ~CSimpleLogger(); /** 記錄檔是否建立或開啟成功 */ bool is_ok() const; /** 輸出日誌,象printf一樣使用,不自動加分行符號 */ void print(const char* format, ...); /** 重新整理日誌,因為使用FILE是帶緩衝的 */ void flush();private: void reset(); /** 複位狀態值 */ void roll_log(); /** 滾動日誌 */private: FILE* _fp; /** 當前正在寫的記錄檔描述符 */ char* _log_buffer; /** 存放日誌的Buffer */ int _bytes_writed; /** 已經寫入的位元組數 */ std::string _log_dir; /** 日誌存放目錄 */ std::string _filename; /** 記錄檔名,不包含目錄部分 */ unsigned int _log_size; /** 單個記錄檔的大小 */ unsigned char _log_numer; /** 日誌滾動的個數 */ unsigned short _record_size; /** 單條日誌的大小,單位為位元組數 */};inline CSimpleLogger::CSimpleLogger( const std::string& log_dir ,const std::string& filename ,unsigned int log_size ,unsigned char log_numer ,unsigned short record_size) :_fp(NULL) ,_log_buffer(NULL) ,_bytes_writed(0) ,_log_dir(log_dir) ,_filename(filename) ,_log_size(log_size) ,_log_numer(log_numer) ,_record_size(record_size){ std::string log_path = log_dir + std::string("/") + filename; _fp = fopen(log_path.c_str(), "a"); if (_fp != NULL) { if (-1 == fseek(_fp, 0, SEEK_END)) { // 失敗,將不會寫日誌 fclose(_fp); _fp = NULL; } else { // 取得已有大小 _bytes_writed = ftell(_fp); // 不能太小氣了 if (_log_size < 1024) { _log_size = 1024; } // 同樣不能太小氣 if (_record_size < 1024) { _record_size = 1024; } _log_buffer = new char[_record_size]; } }}inline CSimpleLogger::~CSimpleLogger(){ if (_fp != NULL) fclose(_fp); delete []_log_buffer;}inline bool CSimpleLogger::is_ok() const{ return _fp != NULL;}inline void CSimpleLogger::print(const char* format, ...){ if (_fp != NULL) { va_list ap; va_start(ap, format); char datetime_buffer[sizeof("2012-12-21 00:00:00")]; // 剛好世界末日 get_current_datetime(datetime_buffer, sizeof(datetime_buffer)); vsnprintf(_log_buffer, _record_size, format, ap); int bytes_writed = fprintf(_fp, "[%s]%s", datetime_buffer, _log_buffer); if (bytes_writed > 0) _bytes_writed += bytes_writed; if (_bytes_writed > static_cast<int>(_log_size)) { roll_log(); } va_end(ap); }}inline void CSimpleLogger::roll_log(){ std::string new_path; // 滾動後的檔案路徑,包含目錄和檔案名稱 std::string old_path; // 滾動前的檔案路徑,包含目錄和檔案名稱 reset(); // 輪迴,一切重新開始 // 曆史滾動 for (int i=_log_numer-1; i>0; --i) { new_path = _log_dir + std::string("/") + _filename + std::string(".") + any2string(i); old_path = _log_dir + std::string("/") + _filename + std::string(".") + any2string(i-1); if (0 == access(old_path.c_str(), F_OK)) { rename(old_path.c_str(), new_path.c_str()); } } if (_log_numer > 0) { // 當前滾動 new_path = _log_dir + std::string("/") + _filename + std::string(".1"); old_path = _log_dir + std::string("/") + _filename; if (0 == access(old_path.c_str(), F_OK)) { rename(old_path.c_str(), new_path.c_str()); } } // 重新建立 _fp = fopen(old_path.c_str(), "w+");}inline void CSimpleLogger::reset(){ _bytes_writed = 0; if (_fp != NULL) { fclose(_fp); _fp = NULL; }}inline void CSimpleLogger::flush(){ if (_fp != NULL) fflush(_fp);}/*** * 測試代碼#include "simple_logger.h"int main(){ CSimpleLogger logger(".", "test.log", 10240); for (int i=0; i<100000; ++i) logger.print("%d ==> abcdefghijklmnopqrestuvwxyz.\n", i); return 0;}*/#if !defined(NOT_WITH_MOOON)SYS_NAMESPACE_END#endif // NOT_WITH_MOOON#endif // MOOON_SYS_SIMPLE_LOGGER_H