// Main.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Common/Logger.h"
#include <iostream>
#include "inifiles.h"
using namespace INIFILE;
using namespace LOGGER;
CLogger g_log(LogLevel_Info, CLogger::GetAppPathA().append("log\\"));
//获取源代码文件名,不用输入参数
DWORD WINAPI Fun(LPVOID lpParamter)
{
while(1)
{
g_log.Fatal("Fun thread display[%s:%d]", CLogger::ExtractFileName(__FILE__).c_str(), __LINE__) ;
Sleep(5000);
}
}
void TestIni(void)
{
TIniFile *iniSet = new TIniFile("..\\Debug\\set.ini");
iniSet->WriteFloat("CodeTool", "float", 13.56);
std::cout << iniSet->ReadFloat("CodeTool", "float", 44.55) << std::endl;
iniSet->WriteBool("CodeTool", "bool", true);
std::cout << iniSet->ReadBool("CodeTool", "bool", false) << std::endl;
iniSet->WriteInteger("CodeTool", "LogLevel", LOGGER::LogLevel_Warning);
LOGGER::EnumLogLevel logLevel = (LOGGER::EnumLogLevel)iniSet->ReadInteger("CodeTool", "LogLevel", LOGGER::LogLevel_Info);
std::cout << "log level:" << logLevel << std::endl;
g_log.ChangeLogLevel(logLevel);
}
void main()
{
HANDLE hThread = CreateThread(NULL, 0, Fun, NULL, 0, NULL);
CloseHandle(hThread);
TestIni();
while (1)
{
g_log.Fatal("TraceFatal [%s:%d]", CLogger::ExtractFileName(__FILE__).c_str(), __LINE__);
g_log.Error("TraceError %s", "sun");
string msg("string messages");
g_log.Warn("TraceWarning %s", msg.c_str());
g_log.Info("TraceInfo");
g_log.Fatal("TraceFatal %d", 2);
g_log.Error("TraceError %f", 441.343567f);
g_log.Warn("TraceWarning");
g_log.Info("TraceInfo");
Sleep(1000);
}
std::cout << "已完成" << std::endl;
getchar();
}
//logger.h
//类名:CLogger
//功能介绍:Win平台日志记录功能,多线程安全,支持写日志级别的设置,日志格式包含日志等级,日志时间,文件名,行号信息
//作者:sunflover 2016-1-15 14:31:27
//修正者:andy 2016-9-11 17:07
#ifndef _LOGGER_H_
#define _LOGGER_H_
#include <Windows.h>
#include <stdio.h>
#include <string>
#include <fstream>
using std::string;
using std::fstream;
namespace LOGGER
{
//日志级别的提示信息
static const string strFatalPrefix = "FATAL <> - ";
static const string strErrorPrefix = "ERROR <> - ";
static const string strWarningPrefix = "WARN <> - ";
static const string strInfoPrefix = "INFO <> - ";
//日志级别枚举
typedef enum EnumLogLevel
{
LogLevel_Stop = 0, //什么都不记录
LogLevel_Fatal =1, //只记录严重错误
LogLevel_Error = 2, //记录严重错误,普通错误
LogLevel_Warning = 3, //记录严重错误,普通错误,警告
LogLevel_Info = 4, //记录严重错误,普通错误,警告,提示信息(也就是全部记录)
};
class CLogger
{
public:
//nLogLevel:日志记录的等级,可空
//strLogPath:日志目录,可空
//strLogName:日志名称,可空
CLogger(EnumLogLevel nLogLevel = LogLevel_Info, const string strLogPath = "", const string strLogName = "");
//析构函数
virtual ~CLogger();
public:
//写严重错误信息
void Fatal(const char *lpcszFormat, ...);
//写错误信息
void Error(const char *lpcszFormat, ...);
//写警告信息
void Warn(const char *lpcszFormat, ...);
//写提示信息
void Info(const char *lpcszFormat, ...);
//改变写日志级别
void ChangeLogLevel(EnumLogLevel nLevel);
//获取程序运行路径
static string GetAppPathA();
//格式化字符串
static string FormatString(const char *lpcszFormat, ...);
static string IntToStr(int val);
//返回完整文件名中的文件名称 (带扩展名),如"mytest.doc"
static string ExtractFileName(const char *szFilePath);
private:
//写文件操作
void Trace(const string &strLog);
//获取当前系统时间
std::string GetTime();
private:
//写日志文件流
fstream m_fout;
//写日志级别
EnumLogLevel m_nLogLevel;
//日志目录
string m_strLogPath;
//日志的名称
string m_strLogName;
//日志文件全路径
string m_strLogFilePath;
//线程同步的临界区变量
CRITICAL_SECTION m_cs;
};
}
#endif
//logger.cpp
#include "stdafx.h"
#include "logger.h"
#include "logger.h"
#include <time.h>
#include <stdarg.h>
#include <direct.h>
#include <vector>
#include <sstream>
#include <Dbghelp.h>
#pragma comment(lib,"Dbghelp.lib")
using std::vector;
namespace LOGGER
{
CLogger::CLogger(EnumLogLevel nLogLevel, const string strLogPath, const string strLogName)
:m_nLogLevel(nLogLevel),
m_strLogPath(strLogPath),
m_strLogName(strLogName)
{
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);
m_strLogName = FormatString("%04d%02d%02d.log", tm1.tm_year + 1900, tm1.tm_mon + 1, tm1.tm_mday); //日志的名称如:20160910.log
}
m_strLogFilePath = m_strLogPath.append(m_strLogName);
//以追加的方式打开文件流
m_fout.open(m_strLogFilePath.c_str(), fstream::app, _SH_DENYNO);
InitializeCriticalSection(&m_cs);
}
//-------------------------------------------------------------------------------------------------------------------------
//析构函数
CLogger::~CLogger()
{
//释放临界区
DeleteCriticalSection(&m_cs);
//关闭文件流
if (m_fout)
{
m_fout.close();
}
}
//-------------------------------------------------------------------------------------------------------------------------
//写严重错误信息
void CLogger::Fatal(const char *lpcszFormat, ...)
{
//判断当前的写日志级别
if (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 = GetTime(); //IntToStr(GetCurrentThreadId()) + " " +
strLog.append(strFatalPrefix).append(strResult);
//写日志文件
Trace(strLog);
}
//-------------------------------------------------------------------------------------------------------------------------
//写错误信息
void CLogger::Error(const char *lpcszFormat, ...)
{
//判断当前的写日志级别
if (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; //获取格式化字符串长度
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 = GetTime();
strLog.append(strErrorPrefix).append(strResult);
//写日志文件
Trace(strLog);
}
//-------------------------------------------------------------------------------------------------------------------------
//写警告信息
void CLogger::Warn(const char *lpcszFormat, ...)
{
//判断当前的写日志级别
if (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; //获取格式化字符串长度
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 = GetTime();
strLog.append(strWarningPrefix).append(strResult);
//写日志文件
Trace(strLog);
}
//-------------------------------------------------------------------------------------------------------------------------
//写一般信息
void CLogger::Info(const char *lpcszFormat, ...)
{
//判断当前的写日志级别
if (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; //获取格式化字符串长度
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 = GetTime();
strLog.append(strInfoPrefix).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("%02d-%02d-%02d %02d:%02d:%02d ", (tm1.tm_year + 1900)%100, 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 (!m_fout.is_open())
{
m_fout.open(m_strLogFilePath.c_str(), fstream::app, _SH_DENYNO);
if (!m_fout)
{
return;
}
}
//写日志信息到文件流
m_fout << strLog.c_str() << std::endl;
//离开临界区
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; //获取格式化字符串长度
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;
}
//-------------------------------------------------------------------------------------------------------------------------
string CLogger::IntToStr(int val)
{
string tmp;
std::stringstream ss;
ss << val;
ss >> tmp;
return tmp;
}
//-------------------------------------------------------------------------------------------------------------------------
//返回完整文件名中的文件名称 (带扩展名),如"mytest.doc"
string CLogger::ExtractFileName(const char *szFilePath)
{
char szDrive[MAX_PATH] = { 0 }, szDir[MAX_PATH] = { 0 }, szFileName[MAX_PATH] = { 0 }, szExt[MAX_PATH] = { 0 };
_splitpath_s(szFilePath, szDrive, szDir, szFileName, szExt);
string fileName = string(szFileName) + szExt;
return fileName;
}
}//end of namespace LOGGER
#pragma once
#include <atlstr.h>
namespace INIFILE
{
class TIniFile
{
public:
TIniFile(const CString FileName);
virtual ~TIniFile();
public:
virtual CString ReadString(const CString Section, const CString Ident, const CString Default);
virtual void WriteString(const CString Section, const CString Ident, const CString Value);
virtual int ReadInteger(const CString Section, const CString Ident, int Default);
virtual void WriteInteger(const CString Section, const CString Ident, int Value);
virtual double ReadFloat(const CString Section, const CString Ident, double Default);
virtual void WriteFloat(const CString Section, const CString Ident, double Value);
virtual bool ReadBool(const CString Section, const CString Ident, bool Default);
virtual void WriteBool(const CString Section, const CString Ident, bool Value);
private:
CString m_FileName;
};
}//end IniFile
#include "stdafx.h"
#include "inifiles.h"
#include <stdlib.h>
#include <sstream>
namespace INIFILE
{
#define MAX_TXTLEN 256 //最大行数
TIniFile::TIniFile(const CString FileName)
{
m_FileName = FileName;
}
TIniFile::~TIniFile()
{
}
//-------------------------------------------------------------------------------------------------------
CString TIniFile::ReadString(const CString Section, const CString Ident, const CString Default)
{
CString strValue;
::GetPrivateProfileString(Section, Ident, Default, strValue.GetBuffer(MAX_TXTLEN), MAX_TXTLEN, m_FileName);
strValue.ReleaseBuffer();
return strValue;
}
//-------------------------------------------------------------------------------------------------------
void TIniFile::WriteString(const CString Section, const CString Ident, const CString Value)
{
::WritePrivateProfileString(Section, Ident, Value, m_FileName);
}
//-------------------------------------------------------------------------------------------------------
int TIniFile::ReadInteger(const CString Section, const CString Ident, int Default)
{
return ::GetPrivateProfileInt(Section, Ident, Default, m_FileName);
}
//-------------------------------------------------------------------------------------------------------
void TIniFile::WriteInteger(const CString Section, const CString Ident, int Value)
{
CString strValue;
strValue.Format("%d", Value);
::WritePrivateProfileString(Section, Ident, strValue, m_FileName);
}
//-------------------------------------------------------------------------------------------------------
double TIniFile::ReadFloat(const CString Section, const CString Ident, double Default)
{
CString strDefault;
strDefault.Format("%lf", Default);
CString strValue;
::GetPrivateProfileString(Section, Ident, strDefault, strValue.GetBuffer(MAX_TXTLEN), MAX_TXTLEN, m_FileName);
strValue.ReleaseBuffer();
std::stringstream stream;
double val;
stream << strValue;
stream >> val;
return val;
}
//-------------------------------------------------------------------------------------------------------
void TIniFile::WriteFloat(const CString Section, const CString Ident, double Value)
{
CString strValue;
strValue.Format("%lf", Value);
::WritePrivateProfileString(Section, Ident, strValue, m_FileName);
}
//-------------------------------------------------------------------------------------------------------
bool TIniFile::ReadBool(const CString Section, const CString Ident, bool Default)
{
CString strDefault, strValue;
strDefault.Format("%d", Default);
::GetPrivateProfileString(Section, Ident, strDefault, strValue.GetBuffer(MAX_TXTLEN), MAX_TXTLEN, m_FileName);
strValue.ReleaseBuffer();
std::stringstream stream;
bool val;
stream << strValue;
stream >> val;
return val;
}
void TIniFile::WriteBool(const CString Section, const CString Ident, bool Value)
{
CString strValue;
strValue.Format("%d", Value);
::WritePrivateProfileString(Section, Ident, strValue, m_FileName);
}
}// end namespace IniFile
程序是基于VS2008的,由于一些低版本的编译器不支持,大家自行改下
m_fout.open(m_strLogFilePath.c_str(), fstream::app, _SH_DENYNO); 改成m_fout.open(m_strLogFilePath.c_str(), fstream::app);
size_t nLength = _vscprintf(lpcszFormat, marker) + 1; //获取格式化字符串长度 _vscprintf这个其它编译器没有的。建议直接采用 size_t nLength = 1024;
_vsnprintf_s换成stdlib标准里的 vsnprintf
另外,如果VS2013烦人的警告 让你把sprintf换成sprintf_s等
在cpp开头加#param warning(disable:4996)
对CLog做了一些改进
andy 2016-9-11 shenzhen
原文来自:http://blog.csdn.net/sunflover454/article/details/49758801