这是参考网上的一个了例子【一个简易的C++日志记录类】写的,我的这个不需要boost,而是改成了用windows API。
这个Log类,使用了单例模式。思路是单独创建一个线程,获取log文本,并将其写入到文件中。
由于是多线程,所以要注意线程同步。
代码
★头文件:
MyLogger.h
#ifndef __INFO_LOGGER__
#define __INFO_LOGGER__
#include <string>
#include <time.h>
#include <stdio.h>
#include <windows.h>
#define MAX_STR_BUF_LEN 30000 //log缓冲
#define TIME_TO_WRITE_LOG 5000 //
enum LOG_LEVLE{
LEVEL_NO = 0,
LEVEL_DEBUG,
LEVEL_ERROR
};
class CInfoLogger{
public:
static CInfoLogger *instace();
std::string LogInfo(LOG_LEVLE level,char *fmt,...);
std::string LogInfo(LOG_LEVLE level,std::string);
void EnterFunction(std::string function) {
LogInfo(LEVEL_ERROR,"Enter function:" + function);
}
void EnterFunction(const char *function) {
LogInfo(LEVEL_ERROR,"Enter function:%s ", function);
}
void LeaveFunction(std::string function) {
LogInfo(LEVEL_ERROR,"Leave function:" + function);
}
void LeaveFunction(const char * function) {
LogInfo(LEVEL_ERROR,"Leave function:%s",function);
}
void SetExit() {m_bRun = false;}
enum TIME_STRING_MODE{
FOR_FILE_NAME,
FOR_TEXT
};
std::string GetCurTimeToString(TIME_STRING_MODE mod) {
char tmp[66];
SYSTEMTIME sys;
GetLocalTime(&sys);
if (mod == FOR_TEXT) {//写入log时用的时间格式
_snprintf(tmp,sizeof(tmp),"%d/%02d/%02d %02d:%02d:%02d.%04d "
,sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute,sys.wSecond,sys.wMilliseconds);
std::string str(tmp);
return (str);
} else if (mod == FOR_FILE_NAME) {//创建文件时用的时间格式,需要用到下划线
_snprintf(tmp,sizeof(tmp),"%d_%02d_%02d %02d_%02d_%02d"
,sys.wYear,sys.wMonth,sys.wDay,sys.wHour,sys.wMinute,sys.wSecond);
std::string str(tmp);
return (str);
}
}
~CInfoLogger(){
SetExit();
if (_instance != NULL) {
delete _instance;
_instance = NULL;
}
}
const char * GetLogFileName() {
return m_strLogFileName.c_str();
}
void setLogLevel(LOG_LEVLE logLevel) {
if ((logLevel == LEVEL_NO)||(logLevel == LEVEL_DEBUG)||(logLevel == LEVEL_ERROR)) {
m_LogLevel = logLevel;
}
}
LOG_LEVLE getLogLevel() {
return m_LogLevel;
}
static void lock() { m_lock = true;}
static void unlock() {m_lock = false;}
static bool isLock() {return m_lock;}
private:
static CInfoLogger *_instance;
static bool m_lock;
HANDLE m_threadHandle;
bool m_bRun;
std::string m_strLogFileName;
std::string m_strWriteStrInfo;
LOG_LEVLE m_LogLevel;
CInfoLogger(void);
void WriteLog(LOG_LEVLE level,std::string strLog);
void WriteLogToFile();
static DWORD WINAPI LogProcStart(PVOID pArg);
};
#endif
★cpp文件:
MyLogger.cpp
#include "MyLogger.h"
CInfoLogger * CInfoLogger::_instance = NULL;//初始化静态变量
bool CInfoLogger::m_lock = false;//初始化静态变量
CInfoLogger::CInfoLogger() {
m_strWriteStrInfo = "";
m_strLogFileName = "C:\\Run_" + GetCurTimeToString(FOR_FILE_NAME) +".log";
m_LogLevel = LEVEL_NO;
m_bRun = true;
m_threadHandle = CreateThread(NULL,0,LogProcStart,this,0,NULL);
}
DWORD CInfoLogger::LogProcStart(PVOID pArg) {
CInfoLogger * CL = NULL;
CL = (CInfoLogger * )pArg;
int nCount = 1;
clock_t preSaveTime = clock();
while(CL->m_bRun) {
Sleep(250);
if ((clock() - preSaveTime ) > TIME_TO_WRITE_LOG) {//开始往文件写的间隔时间
preSaveTime = clock();
CL->WriteLogToFile();
}
}
printf("exit LogProcStart\n");
return 1;
}
void CInfoLogger::WriteLog(LOG_LEVLE level,std::string strLog) {
//if (!m_strWriteStrInfo.empty()){
m_strWriteStrInfo += GetCurTimeToString(FOR_TEXT);
if (level == LEVEL_DEBUG) {
m_strWriteStrInfo += " Debug ";
}
if (level == LEVEL_ERROR) {
m_strWriteStrInfo += " Error ";
}
m_strWriteStrInfo += strLog;
m_strWriteStrInfo += "\n";
//}
if (m_strWriteStrInfo.size() > MAX_STR_BUF_LEN) {
WriteLogToFile();
}
}
void CInfoLogger::WriteLogToFile() {
HANDLE hFile;
DWORD NumberOfBytesRead;
if (!isLock()) {
lock();
hFile = ::CreateFile(m_strLogFileName.c_str(),GENERIC_READ|GENERIC_WRITE,0,NULL,FILE_APPEND_DATA ,FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile != INVALID_HANDLE_VALUE) {
try {
SetFilePointer(hFile,0,NULL,FILE_END);
WriteFile(hFile,m_strWriteStrInfo.c_str(),m_strWriteStrInfo.size(),&NumberOfBytesRead,NULL);
printf("write file success \n");
m_strWriteStrInfo = "";
}catch(std::exception e) {
printf("write file error %s\n",e.what());
}
} else {
printf("open file error\n");
}
CloseHandle(hFile);
unlock();
}
}
///////////////////////////////////////
CInfoLogger *CInfoLogger::instace() {
if (!isLock()) { //由于用的单例模式,所以整个线程只有这一个对象。如果不用锁的话
lock(); //万一两个线程都判断到_instance == NULL,会创建2个对象,违反单一原则
//最好用Mutex,等我有空在进行修改
if (_instance == NULL) {
_instance = new CInfoLogger();
}
unlock();
}
return _instance;
}
std::string CInfoLogger::LogInfo(LOG_LEVLE level,char *fmt,...) {
char out[1024];
va_list body;
va_start(body,fmt);
vsprintf(out,fmt,body);
va_end(body);
std::string str(out);
if (level <= getLogLevel()) {
return str;
}
WriteLog(level,str);
OutputDebugStringA(out);
OutputDebugStringA("\n");
return str;
}
std::string CInfoLogger::LogInfo(LOG_LEVLE level,std::string info) {
if (level <= getLogLevel()) {
return info;
}
WriteLog(level,info);
OutputDebugStringA(info.c_str());
OutputDebugStringA("\n");
return info;
}
/////////////////////////////
//int main () {
// CInfoLogger *d = CInfoLogger::instace();
// int i = 0;
// while(1){
// i++;
// Sleep(1000);
// char * a = "sdgag;agpo";
// d->LogInfo(LEVEL_ERROR,"times i = %s",a);
// //d->SetExit();
// }
// return 1;
//}
/*
* other c file,"extern void CLogInfo(int Level,const char * fmt,...);" ok
* 为了让c文件引用C++的函数
*
*/
//#ifdef __cplusplus
//extern "C"{
//#endif
//void CLogInfo(int Level,const char * fmt,...) {
// char buf[1024];
// va_list body;
// va_start(body,fmt);
// vsprintf(buf,fmt,body);
// va_end(body);
// CInfoLogger::instace()->LogInfo((LOG_LEVLE)Level,buf);
//}
//#ifdef __cplusplus
//}
//#endif