VC++ 轻量级日志输出类CLogCxx

头文件声明(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();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值