版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
<!--一个博主专栏付费入口结束-->
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-d284373521.css">
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-d284373521.css">
<div class="htmledit_views" id="content_views">
-
//logger.h
-
/*
-
//类名:CLogger
-
//功能介绍:Win平台日志记录功能,多线程安全,支持写日志级别的设置,日志格式包含日志等级,日志时间,文件名,行号信息
-
//作者:sunflover 2016-1-15 14:31:27
-
-
//使用方法:
-
1:将logger.h,logger.cpp添加到项目中
-
2:设置logger.cpp的预编译头选项为“不使用预编译头”
-
3:使用代码示例:
-
#include "Logger.h"
-
using namespace LOGGER;
-
CLogger logger(LogLevel_Info,CLogger::GetAppPathA().append("log\\"));
-
-
void main()
-
{
-
logger.TraceFatal("TraceFatal %d", 1);
-
logger.TraceError("TraceError %s", "sun");
-
logger.TraceWarning("TraceWarning");
-
logger.TraceInfo("TraceInfo");
-
-
logger.ChangeLogLevel(LOGGER::LogLevel_Error);
-
-
logger.TraceFatal("TraceFatal %d", 2);
-
logger.TraceError("TraceError %s", "sun2");
-
logger.TraceWarning("TraceWarning");
-
logger.TraceInfo("TraceInfo");
-
}
-
-
-
执行结果:20160126_101329.log文件内容如下
-
Fatal 2016-01-26 10:13:29 TraceFatal 1
-
Error 2016-01-26 10:13:29 TraceError sun
-
Warning 2016-01-26 10:13:29 TraceWarning
-
Info 2016-01-26 10:13:29 TraceInfo
-
Fatal 2016-01-26 10:13:29 TraceFatal 2
-
Error 2016-01-26 10:13:29 TraceError sun2
-
*/
-
-
#ifndef _LOGGER_H_
-
#define _LOGGER_H_
-
#include <Windows.h>
-
#include <stdio.h>
-
#include <string>
-
-
namespace LOGGER
-
{
-
//日志级别的提示信息
-
static
const
std::
string strFatalPrefix =
"Fatal\t";
-
static
const
std::
string strErrorPrefix =
"Error\t";
-
static
const
std::
string strWarningPrefix =
"Warning\t";
-
static
const
std::
string strInfoPrefix =
"Info\t";
-
-
//日志级别枚举
-
typedef
enum EnumLogLevel
-
{
-
LogLevel_Stop =
0,
//什么都不记录
-
LogLevel_Fatal,
//只记录严重错误
-
LogLevel_Error,
//记录严重错误,普通错误
-
LogLevel_Warning,
//记录严重错误,普通错误,警告
-
LogLevel_Info
//记录严重错误,普通错误,警告,提示信息(也就是全部记录)
-
};
-
-
class CLogger
-
{
-
public:
-
//nLogLevel:日志记录的等级,可空
-
//strLogPath:日志目录,可空
-
//strLogName:日志名称,可空
-
CLogger(EnumLogLevel nLogLevel = EnumLogLevel::LogLevel_Info,
const
std::
string strLogPath =
"",
const
std::
string strLogName =
"");
-
//析构函数
-
virtual ~CLogger();
-
public:
-
//写严重错误信息
-
void TraceFatal(const char *lpcszFormat, ...);
-
//写错误信息
-
void TraceError(const char *lpcszFormat, ...);
-
//写警告信息
-
void TraceWarning(const char *lpcszFormat, ...);
-
//写提示信息
-
void TraceInfo(const char *lpcszFormat, ...);
-
//改变写日志级别
-
void ChangeLogLevel(EnumLogLevel nLevel);
-
//获取程序运行路径
-
static
std::
string GetAppPathA();
-
//格式化字符串
-
static
std::
string FormatString(const char *lpcszFormat, ...);
-
private:
-
//写文件操作
-
void Trace(const std::string &strLog);
-
//获取当前系统时间
-
std::
string GetTime();
-
//文件全路径得到文件名
-
const char *path_file(const char *path, char splitter);
-
private:
-
//写日志文件流
-
FILE * m_pFileStream;
-
//写日志级别
-
EnumLogLevel m_nLogLevel;
-
//日志目录
-
std::
string m_strLogPath;
-
//日志的名称
-
std::
string m_strLogName;
-
//日志文件全路径
-
std::
string m_strLogFilePath;
-
//线程同步的临界区变量
-
CRITICAL_SECTION m_cs;
-
};
-
}
-
-
#endif
-
//logger.cpp
-
#include "logger.h"
-
#include <time.h>
-
#include <stdarg.h>
-
#include <direct.h>
-
#include <vector>
-
#include <Dbghelp.h>
-
#pragma comment(lib,"Dbghelp.lib")
-
-
using
std::
string;
-
using
std::
vector;
-
-
namespace LOGGER
-
{
-
CLogger::CLogger(EnumLogLevel nLogLevel,
const
std::
string strLogPath,
const
std::
string strLogName)
-
:m_nLogLevel(nLogLevel),
-
m_strLogPath(strLogPath),
-
m_strLogName(strLogName)
-
{
-
//初始化
-
m_pFileStream =
NULL;
-
if (m_strLogPath.empty())
-
{
-
m_strLogPath = GetAppPathA();
-
}
-
if (m_strLogPath[m_strLogPath.length()
-1] !=
'\\')
-
{
-
m_strLogPath.append(
"\\");
-
}
-
//创建文件夹
-
MakeSureDirectoryPathExists(m_strLogPath.c_str());
-
//创建日志文件
-
if (m_strLogName.empty())
-
{
-
time_t curTime;
-
time(&curTime);
-
tm tm1;
-
localtime_s(&tm1, &curTime);
-
//日志的名称如:201601012130.log
-
m_strLogName = FormatString(
"%04d%02d%02d_%02d%02d%02d.log", tm1.tm_year +
1900, tm1.tm_mon +
1, tm1.tm_mday, tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
-
}
-
m_strLogFilePath = m_strLogPath.append(m_strLogName);
-
-
//以追加的方式打开文件流
-
fopen_s(&m_pFileStream, m_strLogFilePath.c_str(),
"a+");
-
-
InitializeCriticalSection(&m_cs);
-
}
-
-
-
//析构函数
-
CLogger::~CLogger()
-
{
-
//释放临界区
-
DeleteCriticalSection(&m_cs);
-
//关闭文件流
-
if (m_pFileStream)
-
{
-
fclose(m_pFileStream);
-
m_pFileStream =
NULL;
-
}
-
}
-
-
//文件全路径得到文件名
-
const
char *CLogger::path_file(
const
char *path,
char splitter)
-
{
-
return
strrchr(path, splitter) ?
strrchr(path, splitter) +
1 : path;
-
}
-
-
//写严重错误信息
-
void CLogger::TraceFatal(
const
char *lpcszFormat, ...)
-
{
-
//判断当前的写日志级别
-
if (EnumLogLevel::LogLevel_Fatal > m_nLogLevel)
-
return;
-
string strResult;
-
if (
NULL != lpcszFormat)
-
{
-
va_list marker =
NULL;
-
va_start(marker, lpcszFormat);
//初始化变量参数
-
size_t nLength = _vscprintf(lpcszFormat, marker) +
1;
//获取格式化字符串长度
-
std::
vector<
char> vBuffer(nLength,
'\0');
//创建用于存储格式化字符串的字符数组
-
int nWritten = _vsnprintf_s(&vBuffer[
0], vBuffer.size(), nLength, lpcszFormat, marker);
-
if (nWritten >
0)
-
{
-
strResult = &vBuffer[
0];
-
}
-
va_end(marker);
//重置变量参数
-
}
-
if (strResult.empty())
-
{
-
return;
-
}
-
string strLog = strFatalPrefix;
-
strLog.append(GetTime()).append(strResult);
-
-
//写日志文件
-
Trace(strLog);
-
}
-
-
//写错误信息
-
void CLogger::TraceError(
const
char *lpcszFormat, ...)
-
{
-
//判断当前的写日志级别
-
if (EnumLogLevel::LogLevel_Error > m_nLogLevel)
-
return;
-
string strResult;
-
if (
NULL != lpcszFormat)
-
{
-
va_list marker =
NULL;
-
va_start(marker, lpcszFormat);
//初始化变量参数
-
size_t nLength = _vscprintf(lpcszFormat, marker) +
1;
//获取格式化字符串长度
-
std::
vector<
char> vBuffer(nLength,
'\0');
//创建用于存储格式化字符串的字符数组
-
int nWritten = _vsnprintf_s(&vBuffer[
0], vBuffer.size(), nLength, lpcszFormat, marker);
-
if (nWritten >
0)
-
{
-
strResult = &vBuffer[
0];
-
}
-
va_end(marker);
//重置变量参数
-
}
-
if (strResult.empty())
-
{
-
return;
-
}
-
string strLog = strErrorPrefix;
-
strLog.append(GetTime()).append(strResult);
-
-
//写日志文件
-
Trace(strLog);
-
}
-
-
//写警告信息
-
void CLogger::TraceWarning(
const
char *lpcszFormat, ...)
-
{
-
//判断当前的写日志级别
-
if (EnumLogLevel::LogLevel_Warning > m_nLogLevel)
-
return;
-
string strResult;
-
if (
NULL != lpcszFormat)
-
{
-
va_list marker =
NULL;
-
va_start(marker, lpcszFormat);
//初始化变量参数
-
size_t nLength = _vscprintf(lpcszFormat, marker) +
1;
//获取格式化字符串长度
-
std::
vector<
char> vBuffer(nLength,
'\0');
//创建用于存储格式化字符串的字符数组
-
int nWritten = _vsnprintf_s(&vBuffer[
0], vBuffer.size(), nLength, lpcszFormat, marker);
-
if (nWritten >
0)
-
{
-
strResult = &vBuffer[
0];
-
}
-
va_end(marker);
//重置变量参数
-
}
-
if (strResult.empty())
-
{
-
return;
-
}
-
string strLog = strWarningPrefix;
-
strLog.append(GetTime()).append(strResult);
-
-
//写日志文件
-
Trace(strLog);
-
}
-
-
-
//写一般信息
-
void CLogger::TraceInfo(
const
char *lpcszFormat, ...)
-
{
-
//判断当前的写日志级别
-
if (EnumLogLevel::LogLevel_Info > m_nLogLevel)
-
return;
-
string strResult;
-
if (
NULL != lpcszFormat)
-
{
-
va_list marker =
NULL;
-
va_start(marker, lpcszFormat);
//初始化变量参数
-
size_t nLength = _vscprintf(lpcszFormat, marker) +
1;
//获取格式化字符串长度
-
std::
vector<
char> vBuffer(nLength,
'\0');
//创建用于存储格式化字符串的字符数组
-
int nWritten = _vsnprintf_s(&vBuffer[
0], vBuffer.size(), nLength, lpcszFormat, marker);
-
if (nWritten >
0)
-
{
-
strResult = &vBuffer[
0];
-
}
-
va_end(marker);
//重置变量参数
-
}
-
if (strResult.empty())
-
{
-
return;
-
}
-
string strLog = strInfoPrefix;
-
strLog.append(GetTime()).append(strResult);
-
-
//写日志文件
-
Trace(strLog);
-
}
-
-
//获取系统当前时间
-
string CLogger::GetTime()
-
{
-
time_t curTime;
-
time(&curTime);
-
tm tm1;
-
localtime_s(&tm1, &curTime);
-
//2016-01-01 21:30:00
-
string strTime = FormatString(
"%04d-%02d-%02d %02d:%02d:%02d ", tm1.tm_year +
1900, tm1.tm_mon +
1, tm1.tm_mday, tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
-
-
return strTime;
-
}
-
-
//改变写日志级别
-
void CLogger::ChangeLogLevel(EnumLogLevel nLevel)
-
{
-
m_nLogLevel = nLevel;
-
}
-
-
//写文件操作
-
void CLogger::Trace(
const
string &strLog)
-
{
-
try
-
{
-
//进入临界区
-
EnterCriticalSection(&m_cs);
-
//若文件流没有打开,则重新打开
-
if (
NULL == m_pFileStream)
-
{
-
fopen_s(&m_pFileStream, m_strLogFilePath.c_str(),
"a+");
-
if (!m_pFileStream)
-
{
-
return;
-
}
-
}
-
//写日志信息到文件流
-
fprintf(m_pFileStream,
"%s\n", strLog.c_str());
-
fflush(m_pFileStream);
-
//离开临界区
-
LeaveCriticalSection(&m_cs);
-
}
-
//若发生异常,则先离开临界区,防止死锁
-
catch (...)
-
{
-
LeaveCriticalSection(&m_cs);
-
}
-
}
-
-
string CLogger::GetAppPathA()
-
{
-
char szFilePath[MAX_PATH] = {
0 }, szDrive[MAX_PATH] = {
0 }, szDir[MAX_PATH] = {
0 }, szFileName[MAX_PATH] = {
0 }, szExt[MAX_PATH] = {
0 };
-
GetModuleFileNameA(
NULL, szFilePath,
sizeof(szFilePath));
-
_splitpath_s(szFilePath, szDrive, szDir, szFileName, szExt);
-
-
string str(szDrive);
-
str.append(szDir);
-
return str;
-
}
-
-
string CLogger::FormatString(
const
char *lpcszFormat, ...)
-
{
-
string strResult;
-
if (
NULL != lpcszFormat)
-
{
-
va_list marker =
NULL;
-
va_start(marker, lpcszFormat);
//初始化变量参数
-
size_t nLength = _vscprintf(lpcszFormat, marker) +
1;
//获取格式化字符串长度
-
std::
vector<
char> vBuffer(nLength,
'\0');
//创建用于存储格式化字符串的字符数组
-
int nWritten = _vsnprintf_s(&vBuffer[
0], vBuffer.size(), nLength, lpcszFormat, marker);
-
if (nWritten >
0)
-
{
-
strResult = &vBuffer[
0];
-
}
-
va_end(marker);
//重置变量参数
-
}
-
return strResult;
-
}
-
}
有图有真相: