windows下如何实现高效的C的log日志记录
开个线程,用fprintf写文件就是了
下面是我很久之前封装的一个日记工具接口,生成dll后直接调用dll接口就可以了
MyLog.h
#ifndef _TZHYJSGLB_LOG_H_
#define _TZHYJSGLB_LOG_H_
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string>
#include <queue>
#include <string.h>
#include <Windows.h>
#include <process.h>
#include <time.h>
#ifdef LCLOG_API
#else
#define LCLOG_API _declspec(dllimport)
#endif
/**@类名:日志管理类
* @职责:生成并管理日志
* @功能:
*/
//日志文件模式:每天一个日志文件,每月一个日志文件,只有一个日志文件
enum EMyLogModle
{
EL_EVERY_DAY,
EL_EVERY_MON,
EL_ONLYONE
};
class LCLOG_API CMyLog
{
protected:
CMyLog();
~CMyLog();
public:
/**@brief:初始化日志管理类
* @param[in] strLogPath:日志存放路径,不含日志名称
* @return:
* @remark:
*/
static void Init(std::string strLogPath);
/**@brief:设置日志文件模式
* @param[in] eMod:日志模式
* @param[in] strFileName:日志文件名称,日志模式为EL_ONLYONE时,填写该参数
* @return:
* @remark:
*/
static void SetLogFileModle(EMyLogModle eMod,std::string strFileName ="");
/**@brief:写入日志
* @param[in]:日志内容
* @return:
* @remark:
*/
static std::string NewLog(std::string strLog);
static std::string NewLog(const char* pszFormat,...);
/**@brief:释放资源
* @param[]
* @return:
* @remark:
*/
static void Release();
private:
static std::string LogOutQueue(); //日志出队
static void* CreateLogFile(void*); //创建日志文件
static void GetLogFile(); //获取日志文件指针
static bool IsNeedNewFile(std::string strFile); //判断是否需要新的日志文件
static std::string GetTime(); //获取当时时间
private:
static std::string m_strLogPath; //日志文件路径
static std::string m_strSingleLogName; //单日志文件名称
static std::string m_strCurrentLog; //当前日志文件名称
static EMyLogModle m_eModle; //日志文件类型
static std::queue<std::string>* m_pqLogManager; //日志管理队列
static HANDLE m_mutexQueue; //日志队列锁
static FILE* m_Filelog; //日志文件
//static char m_cTmp[1024]; //缓冲区
static HANDLE m_hWnd; //日志线程ID
};
#endif
MyLog.cpp
//日志管理类实现
#ifdef WIN32
#define LCLOG_API _declspec(dllexport)
#endif
#include "MyLog.h"
//////////////////////////////////////////////////////////////////////////////////////
// 静态变量 //
//////////////////////////////////////////////////////////////////////////////////////
std::string CMyLog::m_strLogPath; //日志文件路径
std::string CMyLog::m_strSingleLogName; //单日志文件名称
std::string CMyLog::m_strCurrentLog; //当前日志文件名称
EMyLogModle CMyLog::m_eModle; //日志文件类型
std::queue<std::string>* CMyLog::m_pqLogManager; //日志管理队列
HANDLE CMyLog::m_mutexQueue; //日志队列锁
FILE* CMyLog::m_Filelog; //日志文件
//char CMyLog::m_cTmp[1024]; //缓冲区
HANDLE CMyLog::m_hWnd; //日志线程ID
CMyLog::CMyLog(){}
CMyLog::~CMyLog(){}
//////////////////////////////////////////////////////////////////////////////////////
// 对外接口 //
//////////////////////////////////////////////////////////////////////////////////////
//初始化日志管理类相关成员
void CMyLog::Init(std::string strLogPath)
{
//默认为每天一个日志文件
m_eModle = EL_EVERY_DAY;
//清空日志队列
m_pqLogManager = NULL;
m_pqLogManager = new std::queue<std::string>;
//初始化互斥锁
m_mutexQueue = ::CreateMutex(NULL, FALSE, NULL);
//初始化日志文件
m_Filelog = NULL;
m_strLogPath = strLogPath;
m_strSingleLogName = "";
m_strCurrentLog = " ";
//memset(m_cTmp,0,1024);
//启动日记线程
m_hWnd = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CreateLogFile, NULL, 0, 0);
}
//设置日志文件模式
void CMyLog::SetLogFileModle( EMyLogModle eMod ,std::string strFileName)
{
m_eModle = eMod;
if (eMod == EL_ONLYONE)
{
m_strSingleLogName = strFileName;
}
}
//写入日志
std::string CMyLog::NewLog( std::string strLog )
{
std::string strTime = GetTime();
strTime += strLog;
WaitForSingleObject(m_mutexQueue, INFINITE);
m_pqLogManager->push(strTime);//strLog
::ReleaseMutex(m_mutexQueue);
return strLog;
}
//写入日志
std::string CMyLog::NewLog( const char* pszFormat,... )
{
//WINDOWS
//va_list args;
//int len = 0;
//// retrieve the variable arguments
//va_start( args, pszFormat );
//len = _vscprintf( pszFormat, args ) +1;// _vscprintf doesn't count terminating '\0'
//char* buffer = new char[len * sizeof(char)];
//memset(buffer,0,len * sizeof(char));
//vsprintf( buffer, pszFormat, args ); // C4996
//// Note: vsprintf is deprecated; consider using vsprintf_s instead
//
//std::string strTmp = (std::string)buffer;
//NewLog(strTmp);
//delete []buffer;
//buffer = NULL;
//LINUX
va_list args;
va_start( args, pszFormat );
char cTmp[1024] ={0};
//memset(m_cTmp,0,1024);
int nRes = vsprintf(cTmp, pszFormat, args );
va_end(args);
//printf("%s\n",m_cTmp);
std::string strTmp =(std::string)cTmp;
NewLog(strTmp);
return strTmp;
}
void CMyLog::Release()
{
TerminateThread(m_hWnd, 0);//结束日志线程
//清空队列
if (m_pqLogManager != NULL)
{
WaitForSingleObject(m_mutexQueue,INFINITE);
while(m_pqLogManager->size() > 0)
{
m_pqLogManager->pop();
}
::ReleaseMutex(m_mutexQueue);
delete m_pqLogManager;
m_pqLogManager = NULL;
}
::CloseHandle(m_mutexQueue);
}
//////////////////////////////////////////////////////////////////////////////////////
// 内部成员函数 //
//////////////////////////////////////////////////////////////////////////////////////
//日志出队
std::string CMyLog::LogOutQueue()
{
std::string strLog = "";
WaitForSingleObject(m_mutexQueue, INFINITE);
strLog = m_pqLogManager->front();
m_pqLogManager->pop();
::ReleaseMutex(m_mutexQueue);
return strLog;
}
//创建日志文件:后台线程
void* CMyLog::CreateLogFile(void*)
{
while(1)
{
if (m_pqLogManager == NULL)
{
return NULL;
}
if (m_pqLogManager->size() == 0)
{
Sleep(500);
}else
{
//获取日志信息
std::string strLog = LogOutQueue();
//获取日志文件信息
GetLogFile();
//日志写入日志文件
if (m_Filelog != NULL)
{
fwrite(strLog.c_str(),strLog.length(),1,m_Filelog);
fflush(m_Filelog);
/*fclose(m_Filelog);
m_Filelog = NULL;*/
}
}
}
}
//获取日志文件指针
void CMyLog::GetLogFile()
{
if (m_eModle == EL_ONLYONE)//单一日志模式
{
if (m_Filelog == NULL)
{
std::string strFileNameOnly = m_strLogPath + m_strSingleLogName;
m_Filelog = fopen(strFileNameOnly.c_str(),"a+");
}else
return;
}else//其他模式
{
//获取当天日期
time_t now;
struct tm* timeinfo;
time(&now);
timeinfo = localtime(&now);
std::string strTmp = "";
char cTmp[15];
memset(cTmp,0,15);
//根据模式判断是否需要更换日志文件
if (m_eModle == EL_EVERY_MON)
{
sprintf(cTmp,"%4d%02d.log",(int)1900+timeinfo->tm_year,(int)1+timeinfo->tm_mon);
}else if (m_eModle == EL_EVERY_DAY)
{
sprintf(cTmp,"%4d%02d%02d.log",(int)1900+timeinfo->tm_year,(int)1+timeinfo->tm_mon,(int)timeinfo->tm_mday);
}else
return;
if (IsNeedNewFile(cTmp))//需要重新生成日志文件
{
if (m_Filelog != NULL)//如果原始日志文件未关闭
{
fclose(m_Filelog);
m_Filelog = NULL;
}
//重新生成日志文件
m_strCurrentLog = (std::string)cTmp;
std::string strFileName = m_strLogPath + m_strCurrentLog;
m_Filelog = fopen(strFileName.c_str(),"a+");
}else
return;
}
return;
}
//判断是否需要新的日志文件
bool CMyLog::IsNeedNewFile(std::string strFile)
{
if (m_Filelog == NULL)//日志指针为空
{
return true;
}else
{
if (m_strCurrentLog.compare(" ") == 0)//还没有生成过日志文件
{
return true;
}else//生成过日志文件
{
if (m_strCurrentLog.compare(strFile.c_str()) == 0)//跟当前日期相同,不需要重新生成
{
return false;
}else//跟当前日期不同,需要重新生成
return true;
}
}
}
//获取时间
std::string CMyLog::GetTime()
{
time_t tmNow = time(NULL);
struct tm *local;
local = localtime(&tmNow);
char cTmp[22] = {0};
sprintf(cTmp,"%d-%d-%d %d:%d:%d ",local->tm_year+1900,local->tm_mon+1,local->tm_mday,local->tm_hour,local->tm_min,local->tm_sec);
return (std::string)cTmp;
}