本例展示一个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下的日志输出小工具就展示完毕了。