WIN32下简单方便的日志输出工具类,支持多线程

本例展示一个WIN32下用来输出日志的小工具LogLite.
因为比较简单,我们就直入主题吧.
定义用于输出日志的类CWriteLogLib

.h

/
#ifndef __WRITELOG_H__
#define __WRITELOG_H__

#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <shlwapi.h>
#include <wchar.h>

#pragma comment (lib, "shlwapi.lib")

namespace	LogLite //lite log
{

enum enType_LogType{
	eLogType_FATAL = 0,
	eLogType_ERROR,
	eLogType_WARN,
	eLogType_INFO,
	eLogType_DEBUG,
	eLogType_TRACE,
};

void SetLogInfo(const wchar_t* pPath, const wchar_t* pLogFileName);
void SetLogLevel(int nLevel);
void LOGGR_TRACE(const wchar_t* Format, ...);
void LOGGR_DEBUG(const wchar_t* Format, ...);
void LOGGR_INFO(const wchar_t* Format, ...);
void LOGGR_WARN(const wchar_t* Format, ...);
void LOGGR_ERROR(const wchar_t* Format, ...);
void LOGGR_FATAL(const wchar_t* Format, ...);

class CWriteLogLib
{
public:
	static CWriteLogLib* GetInstance();
	static void DelInstance();

public:
	BOOL bInitFunc(const wchar_t* pPath, const wchar_t* pLogFileName);
	void UnitFunc();

	void PrintLogInfo(int nLevel,int Line, const wchar_t* Format, ...);
	void PrintLogInfoV(int nLevel, int Line, const wchar_t* Format, va_list vl);
	void WriteLogInfo(int nLevel, const wchar_t* pLogInfo, int Line);

	void SetLogLevel(int nLevel)
	{
		if (nLevel >= 0 && nLevel <= eLogType_TRACE)
		{
			m_enLogType = (enType_LogType)nLevel;
		}
	}

	int GetLogLevel()
	{
		return (int)m_enLogType;
	}

protected:
	CWriteLogLib(void);
	~CWriteLogLib(void);

	void ChangeLogFileName();

private:
	static CWriteLogLib* m_pInstance;

	wchar_t	 m_szPath[MAX_PATH];
	wchar_t 	szLogInfo[1024];
	int		m_nLineCount;
	int		m_nFileCount;
	wchar_t 	m_szLogFile[MAX_PATH];
	wchar_t 	m_szLogFileName[32];

	BOOL	m_bInit;
	wchar_t 	m_szLogLevelStr[6][32];

	enType_LogType	m_enLogType;

	CRITICAL_SECTION m_CriticalSection;
};

} // lite log

#endif

.cpp

#include "stdafx.h"
#include "WriteLogLib.h"


void LogLite::SetLogInfo(const wchar_t* pPath, const wchar_t* pLogFileName)
{
	CWriteLogLib::GetInstance()->bInitFunc(pPath, pLogFileName);
}

void LogLite::SetLogLevel(int nLevel)
{
	CWriteLogLib::GetInstance()->SetLogLevel(nLevel);
}

void LogLite::LOGGR_TRACE(const wchar_t* Format, ...)
{
	int nLogLevel = CWriteLogLib::GetInstance()->GetLogLevel();
	if (nLogLevel >= eLogType_TRACE)
	{
		va_list list;
		va_start(list, Format);
		CWriteLogLib::GetInstance()->PrintLogInfoV(eLogType_TRACE, __LINE__, Format, list);
		va_end(list);
	}
}
void LogLite::LOGGR_DEBUG(const wchar_t* Format, ...)
{
	int nLogLevel = CWriteLogLib::GetInstance()->GetLogLevel();
	if (nLogLevel >= eLogType_DEBUG)
	{
		va_list list;
		va_start(list, Format);
		CWriteLogLib::GetInstance()->PrintLogInfoV(eLogType_DEBUG,__LINE__, Format, list);
		va_end(list);
	}
}
void LogLite::LOGGR_INFO(const wchar_t* Format, ...)
{
	int nLogLevel = CWriteLogLib::GetInstance()->GetLogLevel();
	if (nLogLevel >= eLogType_INFO)
	{
		va_list list;
		va_start(list, Format);
		CWriteLogLib::GetInstance()->PrintLogInfoV(eLogType_INFO,__LINE__, Format, list);
		va_end(list);
	}
}
void LogLite::LOGGR_WARN(const wchar_t* Format, ...)
{
	int nLogLevel = CWriteLogLib::GetInstance()->GetLogLevel();
	if (nLogLevel >= eLogType_WARN)
	{
		va_list list;
		va_start(list, Format);
		CWriteLogLib::GetInstance()->PrintLogInfoV(eLogType_WARN,__LINE__, Format, list);
		va_end(list);
	}
}
void LogLite::LOGGR_ERROR(const wchar_t* Format, ...)
{
	int nLogLevel = CWriteLogLib::GetInstance()->GetLogLevel();
	if (nLogLevel >= eLogType_ERROR)
	{
		va_list list;
		va_start(list, Format);
		CWriteLogLib::GetInstance()->PrintLogInfoV(eLogType_ERROR,__LINE__, Format, list);
		va_end(list);
	}
}
void LogLite::LOGGR_FATAL(const wchar_t* Format, ...)
{
	int nLogLevel = CWriteLogLib::GetInstance()->GetLogLevel();
	if (nLogLevel >= eLogType_FATAL)
	{
		va_list list;
		va_start(list, Format);
		CWriteLogLib::GetInstance()->PrintLogInfoV(eLogType_FATAL,__LINE__, Format, list);
		va_end(list);
	}
}


LogLite::CWriteLogLib* LogLite::CWriteLogLib::m_pInstance = NULL;
LogLite::CWriteLogLib::CWriteLogLib(void)
{
	m_bInit = FALSE;
	::InitializeCriticalSection(&m_CriticalSection);
}

LogLite::CWriteLogLib::~CWriteLogLib(void)
{
	::DeleteCriticalSection(&m_CriticalSection);
}

LogLite::CWriteLogLib* LogLite::CWriteLogLib::GetInstance()
{
	if (m_pInstance == NULL)
	{
		m_pInstance = new CWriteLogLib();
	}
	return m_pInstance;
}

void LogLite::CWriteLogLib::DelInstance()
{
	if (m_pInstance != NULL)
	{
		delete m_pInstance;
		m_pInstance = NULL;
	}
}
void LogLite::CWriteLogLib::UnitFunc()
{
	m_bInit = FALSE;
}

BOOL LogLite::CWriteLogLib::bInitFunc(const wchar_t* pPath, const wchar_t* pLogFileName)
{
	lstrcpyW(m_szPath, pPath);
	int nLen = (int)lstrlenW(m_szPath);

	m_enLogType = eLogType_FATAL;

	lstrcpyW(&m_szLogLevelStr[eLogType_FATAL][0],L"FATAL");
	lstrcpyW(&m_szLogLevelStr[eLogType_ERROR][0], L"ERROR");
	lstrcpyW(&m_szLogLevelStr[eLogType_WARN][0], L"WARN ");
	lstrcpyW(&m_szLogLevelStr[eLogType_INFO][0], L"INFO ");
	lstrcpyW(&m_szLogLevelStr[eLogType_DEBUG][0], L"DEBUG");
	lstrcpyW(&m_szLogLevelStr[eLogType_TRACE][0], L"TRACE");

	m_nLineCount = 0;
	srand((UINT)time(NULL));
	m_nFileCount = rand();
	m_nFileCount = 0;
	memset(m_szLogFilePath, 0, sizeof(m_szLogFilePath));
	INT32 nFileNameLen = lstrlenW(pLogFileName);
	if (nFileNameLen > 0 && nFileNameLen < 64)
	{
		memset(m_szLogFileName, 0, sizeof(m_szLogFileName));
		wcsncpy_s(m_szLogFileName, pLogFileName, nFileNameLen);
	}
	else
	{
		memset(m_szLogFileName, 0, sizeof(m_szLogFileName));
		lstrcpyW(m_szLogFileName, L"loglite");
	}
	ChangeLogFileName();

	m_bInit = TRUE;
	return TRUE;
}

void LogLite::CWriteLogLib::WriteLogInfo(int nLevel, const wchar_t* pLogInfo, int Line)
{
#ifdef _DEBUG
	wprintf(pLogInfo);
#endif
	if (!m_bInit) return;
	if (nLevel < eLogType_FATAL || nLevel > eLogType_TRACE) return;

	::EnterCriticalSection(&m_CriticalSection);
	m_nLineCount++;
	if (m_nLineCount == 30000)
	{
		m_nFileCount++;
		m_nLineCount = 0;
		ChangeLogFileName();
	}
	FILE* fp = NULL;
	//errno_t errLog = fopen_s(&fp, m_szLogFile, "at+,ccs=UNICODE");
	errno_t errLog = _wfopen_s(&fp, m_szLogFilePath, L"ab+");
	if (fp != NULL)
	{
		wchar_t szTemp[32] = { 0 };
		time_t	tt;
		time(&tt);
		tm time1 = { 0 };
		errno_t errTime = localtime_s(&time1, &tt);

		swprintf_s(szTemp, 32, L"%04d-%02d-%02d %02d:%02d:%02d",
			time1.tm_year + 1900, time1.tm_mon + 1, time1.tm_mday, time1.tm_hour, time1.tm_min, time1.tm_sec);
		wchar_t	szDesc[64] = { 0 };
		swprintf_s(szDesc, L"\n%15s [%s(%d)][%s]*** ", szTemp, m_szLogFileName, GetCurrentProcessId(),m_szLogLevelStr[nLevel]);
		
		fputws(szDesc, fp);
		fputws(pLogInfo, fp);

		fclose(fp);
	}
	::LeaveCriticalSection(&m_CriticalSection);
};

void LogLite::CWriteLogLib::PrintLogInfo(int nLevel,int Line, const wchar_t* Format, ...)
{
	va_list vl;
	va_start(vl, Format);
	_vsnwprintf_s(szLogInfo, 1020, 1000, Format, vl);
	lstrcatW(szLogInfo, L"\n");
	va_end(vl);
	WriteLogInfo(nLevel,szLogInfo, Line);
}

void LogLite::CWriteLogLib::PrintLogInfoV(int nLevel,int Line, const wchar_t* Format, va_list vl)
{
	_vsnwprintf_s(szLogInfo, 1020, 1000, Format, vl);
	WriteLogInfo(nLevel,szLogInfo, Line);
}

void LogLite::CWriteLogLib::ChangeLogFileName()
{
	wsprintfW(m_szLogFilePath, L"%s%s.log", m_szPath, m_szLogFileName);
	//if (::PathFileExistsW(m_szLogFile))
	{
		//改名
		wchar_t szTemp[32] = { 0 };
		time_t	tt;
		time(&tt);
		tm time1 = { 0 };
		errno_t errTime = localtime_s(&time1, &tt);
		swprintf_s(szTemp, 32, L"%04d%02d%02d%02d%02d%02d",
			time1.tm_year + 1900, time1.tm_mon + 1, time1.tm_mday, time1.tm_hour, time1.tm_min, time1.tm_sec);
		wchar_t szNewLogFile[MAX_PATH] = { 0 };
		swprintf_s(szNewLogFile, L"%s/%s-%s.log", m_szPath, m_szLogFileName, szTemp);
		//MoveFileW(m_szLogFile, szOldLogFile);
		lstrcpyW(m_szLogFilePath, szNewLogFile);
	}
}

接下来实现一个main函数来展示一下如何使用这个小东西(我的工程是Qt工程).

main.cpp

#include "writelogtest.h"
#include <QtWidgets/QApplication>

#include "writelog.h"

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	WriteLogTest twindow;
	twindow.show();

	
	LogLite::SetLogInfo(L"./log", L"log");
	LogLite::SetLogLevel(LogLite::eLogType_TRACE);
	LogLite::LOGGR_DEBUG(L"init log ok. line(%d)", 13);



	int res = a.exec();

	LogLite::LOGGR_DEBUG(L"app quit. line(%d)", 19);

	return res;
}

运行之后在程序的工作目录就会产生对应的日志文件:

(如果目标目录有相同的文件则会自动将文件名+上时间日期,上图说明我这个程序运行了3次)

打开其中一个日志文件看到内容:

至此,这二个WIN32下的日志输出小工具就展示完毕了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值