头文件声明(CLogCxx.h):
#pragma once
#include <Windows.h>
/*
# 日志文件内容格式
[global.logger]
global.logger=ACTIVE
global.debugLogger=DEBUG
global.debugWrite=APPEND
global.console.logger=DEACTIVE
global.console.debugLogger=TRACE
*/
//
#include "SingleInstanceBase.h"
typedef void (CALLBACK* FPLOGRECVCALLBACK)(LPVOID pUser, char* pBuffer, DWORD dwLength);
class CLogCxx: public SingleInstanceBase<CLogCxx>
{
public:
CLogCxx(void);
~CLogCxx(void);
enum LogLevel
{
llTRACE,
llDEBUG,
llINFO,
llWARN,
llERROR,
llFATAL,
};
public:
// 日志接收回调函数
FPLOGRECVCALLBACK m_pfnLogRecvCallback;
// 日志接收回调用户
LPVOID m_pfnLogRecvCallbackUser;
private:
// 是否激活写日志文件
BOOL m_bActive;
// 日志配置文件,默认应用程序名称.ini
CString m_strConfigFile;
// 互斥锁
CCriticalSection m_csLock;
// 程序工作目录
CString m_strWorkDir;
// 当前日志级别
LogLevel m_llCurLog;
// 删除过期无用的日志文件
void DeleteUnusableLog(int nDefaultSaveDay = 3);
// 写日志
void Write(LogLevel level, LPCTSTR lpszLog);
void Write(LPCTSTR pszFileName, LPCTSTR pszLog);
// 清空日志内容
void EmptyFile();
public:
// 设置日志接收回调
void SetRecvCallback(FPLOGRECVCALLBACK pLogRecvCallback, LPVOID pUser);
// 设置配置文件名称
void SetConfFile(const char* lpszFileName);
// 根据日志级别输出日志内容
void Trace(const char *lpszFormat, ...);
void Debug(const char *lpszFormat, ...);
void Info(const char *lpszFormat, ...);
void Warn(const char *lpszFormat, ...);
void Error(const char *lpszFormat, ...);
void Fatal(const char *lpszFormat, ...);
};
源码实现(CLogCxx.cpp):
#include "StdAfx.h"
#include "CLogCxx.h"
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
_MACRO_SINGLETON_(CLogCxx)
CLogCxx::CLogCxx(void)
{
m_llCurLog = llTRACE;
m_bActive = FALSE;
m_pfnLogRecvCallback = NULL;
m_pfnLogRecvCallbackUser = NULL;
}
CLogCxx::~CLogCxx(void)
{
m_bActive = FALSE;
m_pfnLogRecvCallback = NULL;
m_pfnLogRecvCallbackUser = NULL;
}
void CLogCxx::EmptyFile()
{
SYSTEMTIME tm = { 0 };
GetLocalTime(&tm);
char szTime[_MAX_PATH + 1];
_snprintf_s(szTime, _MAX_PATH,
"%02d:%02d:%02d...%03d",
tm.wHour,
tm.wMinute,
tm.wSecond,
tm.wMilliseconds);
CString sLogFileName;
sLogFileName.Format("%s\\系统日志\\%4d-%02d-%02d.Log", m_strWorkDir, tm.wYear, tm.wMonth, tm.wDay);
// 判断日志文件是否存在
if (INVALID_FILE_ATTRIBUTES == GetFileAttributes(sLogFileName))
return;
CStdioFile f;
CFileException fe;
if (f.Open(sLogFileName, CFile::modeWrite | CFile::modeCreate, &fe) == FALSE)
return;
f.Close();
}
void CLogCxx::SetRecvCallback(FPLOGRECVCALLBACK pLogRecvCallback, LPVOID pUser)
{
m_pfnLogRecvCallback = pLogRecvCallback;
m_pfnLogRecvCallbackUser = pUser;
}
void CLogCxx::Write(LPCTSTR pszFileName, LPCTSTR pszLog)
{
if (m_bActive == FALSE) return;
if ( strlen(pszFileName)==0 ) return;
CStdioFile f;
CFileException fe;
CString s;
if (f.Open(pszFileName, CFile::modeWrite | CFile::modeCreate |
CFile::modeNoTruncate, &fe) == FALSE)
{
return;
}
try
{
f.SeekToEnd();
s.Format("%s\n", pszLog);
f.WriteString(s);
}
catch (CException* e)
{
e->Delete();
}
f.Close();
}
#include <algorithm>
#include <vector>
using namespace std;
BOOL SortStringProc(const CString &v1, const CString &v2)
{
return _stricmp(v1, v2) < 0;
}
void CLogCxx::DeleteUnusableLog(int nDefaultSaveDay/* = 3*/)
{
CString strFolder;
strFolder.Format("%s\\系统日志\\", m_strWorkDir);
UINT nFindCount = 0;
CFileFind FileFind;
BOOL bFound = FileFind.FindFile(strFolder + _T("*.log"));
CString strNewFolder;
std::vector<CString> vecLogFiles;
while (bFound)
{
bFound = FileFind.FindNextFile();
if (FileFind.IsDots())
continue;
if (!FileFind.IsDirectory())
{
vecLogFiles.push_back(FileFind.GetFilePath());
}
}
FileFind.Close();
if (vecLogFiles.size() > nDefaultSaveDay)
{
std::sort(vecLogFiles.begin(), vecLogFiles.end(), SortStringProc);
while (vecLogFiles.size() > nDefaultSaveDay)
{
// 按照日期排序
std::vector<CString>::iterator iter = vecLogFiles.begin();
::DeleteFile(*iter);
vecLogFiles.erase(iter);
}
}
}
void CLogCxx::SetConfFile(const char* lpszFileName)
{
m_strConfigFile = lpszFileName;
TCHAR* szResult = new TCHAR[_MAX_PATH + 1];
memset(szResult, 0x00, _MAX_PATH + 1);
GetPrivateProfileString(_T("global.logger"), _T("global.logger"), _T(""), szResult, _MAX_PATH, lpszFileName);
m_bActive = (_tcsicmp(szResult, _T("ACTIVE")) == 0);
if (!m_bActive)
return;
DWORD dwLen = GetCurrentDirectory(_MAX_PATH, m_strWorkDir.GetBufferSetLength(_MAX_PATH + 1));
m_strWorkDir.ReleaseBuffer();
char szLogDebugPath[_MAX_PATH + 1] = { 0 };
_snprintf_s(szLogDebugPath, _MAX_PATH + 1, "%s\\系统日志\\", (LPSTR)(LPCTSTR)m_strWorkDir);
if (!::PathFileExists(szLogDebugPath))
::MakeSureDirectoryPathExists(szLogDebugPath);
DeleteUnusableLog();
memset(szResult, 0x00, _MAX_PATH + 1);
GetPrivateProfileString(_T("global.logger"), _T("global.debugLogger"), _T(""), szResult, _MAX_PATH, lpszFileName);
if (_tcsicmp(szResult, _T("DEBUG")) == 0)
m_llCurLog = llDEBUG;
else if (_tcsicmp(szResult, _T("INFO")) == 0)
m_llCurLog = llINFO;
else if (_tcsicmp(szResult, _T("WARN")) == 0)
m_llCurLog = llWARN;
else if (_tcsicmp(szResult, _T("ERROR")) == 0)
m_llCurLog = llERROR;
else if (_tcsicmp(szResult, _T("FATAL")) == 0)
m_llCurLog = llFATAL;
else
m_llCurLog = llTRACE;
memset(szResult, 0x00, _MAX_PATH + 1);
GetPrivateProfileString(_T("global.logger"), _T("global.debugWrite"), _T(""), szResult, _MAX_PATH, lpszFileName);
if (_tcsicmp(szResult, _T("APPEND")) != 0)
EmptyFile();
}
void CLogCxx::Write(LogLevel level, LPCTSTR lpszLog)
{
SYSTEMTIME tm = { 0 };
GetLocalTime(&tm);
char szTime[_MAX_PATH + 1];
_snprintf_s(szTime, _MAX_PATH,
"%02d:%02d:%02d...%03d",
tm.wHour,
tm.wMinute,
tm.wSecond,
tm.wMilliseconds);
CString strLog;
if (level==llTRACE)
strLog.Format("%s - %s", szTime, lpszLog);
else if (level == llDEBUG)
strLog.Format("%s - [DEBUG] %s", szTime, lpszLog);
else if (level == llINFO)
strLog.Format("%s - [INFO] %s", szTime, lpszLog);
else if (level == llWARN)
strLog.Format("%s - [WARN] %s", szTime, lpszLog);
else if (level == llERROR)
strLog.Format("%s - [ERROR] %s", szTime, lpszLog);
else
return;
CString sLogFileName;
sLogFileName.Format("%s\\系统日志\\%4d-%02d-%02d.Log", m_strWorkDir, tm.wYear, tm.wMonth, tm.wDay);
Write(sLogFileName, strLog);
if (m_pfnLogRecvCallback)
m_pfnLogRecvCallback(m_pfnLogRecvCallbackUser, (LPSTR)(LPCSTR)strLog, strLog.GetLength());
}
void CLogCxx::Trace(const char *lpszFormat, ...)
{
if (m_llCurLog > llTRACE) return;
m_csLock.Lock();
CString strText;
va_list argptr;
va_start(argptr, lpszFormat);
strText.FormatV(lpszFormat, argptr);
va_end(argptr);
Write(llTRACE, strText);
m_csLock.Unlock();
}
void CLogCxx::Debug(const char *lpszFormat, ...)
{
if (m_llCurLog > llDEBUG) return;
m_csLock.Lock();
CString strText;
va_list argptr;
va_start(argptr, lpszFormat);
strText.FormatV(lpszFormat, argptr);
va_end(argptr);
Write(llDEBUG, strText);
m_csLock.Unlock();
}
void CLogCxx::Info(const char *lpszFormat, ...)
{
if (m_llCurLog > llINFO) return;
m_csLock.Lock();
CString strText;
va_list argptr;
va_start(argptr, lpszFormat);
strText.FormatV(lpszFormat, argptr);
va_end(argptr);
Write(llINFO, strText);
m_csLock.Unlock();
}
void CLogCxx::Warn(const char *lpszFormat, ...)
{
if (m_llCurLog > llWARN) return;
m_csLock.Lock();
CString strText;
va_list argptr;
va_start(argptr, lpszFormat);
strText.FormatV(lpszFormat, argptr);
va_end(argptr);
Write(llWARN, strText);
m_csLock.Unlock();
}
void CLogCxx::Error(const char *lpszFormat, ...)
{
if (m_llCurLog > llERROR) return;
m_csLock.Lock();
CString strText;
va_list argptr;
va_start(argptr, lpszFormat);
strText.FormatV(lpszFormat, argptr);
va_end(argptr);
Write(llERROR, strText);
m_csLock.Unlock();
}
void CLogCxx::Fatal(const char *lpszFormat, ...)
{
if (m_llCurLog > llFATAL) return;
m_csLock.Lock();
CString strText;
va_list argptr;
va_start(argptr, lpszFormat);
strText.FormatV(lpszFormat, argptr);
va_end(argptr);
Write(llFATAL, strText);
m_csLock.Unlock();
}