头文件声明(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;// 日志配置文件,默认应用程序名称.iniCString 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 "LogCxx.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;elsem_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);elsereturn;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();
}