文档章节

简单好用的C++日志组件代码

g
 gzstyxb
发布于 2013/11/19 17:36
字数 1283
阅读 623
收藏 11

1、特点:

  • 无需打开、关闭日志文件操作,直接存储。
  • 同时支持UNICODE、多字节类型以及二进制格式存储。
  • 文件大小超过限制,自动备份;备份文件数超过限制,自动删除。
  • 超过3秒没日志写入,文件缓存自动写盘。确保日志尽量不因其它原因导致丢失。

2、代码:

头文件代码如下:

#pragma once
#ifndef _STRSTREAM_
#include <sstream>
#endif

#define WRITE_SIMPLE_LOGGER

namespace SIMPLE_LOGGER
{

#ifdef WRITE_SIMPLE_LOGGER

#define LOGGER_WRITE_W(Value) { \
	std::wostringstream logstream; logstream << Value; std::wstring logstring = logstream.str(); \
	SIMPLE_LOGGER::S_WriteW(0, logstring.c_str(), __FILE__, __LINE__); }

#define LOGGER_WRITE_W2(Value) { \
	std::wostringstream logstream; logstream << Value; std::wstring logstring = logstream.str(); \
	SIMPLE_LOGGER::S_WriteW(0, logstring.c_str(), __FILE__, __LINE__, TRUE); }

#define LOGGER_WRITE_A(Value) { \
	std::ostringstream logstream; logstream << Value; std::string logstring = logstream.str(); \
	SIMPLE_LOGGER::S_WriteA(0, logstring.c_str(), __FILE__, __LINE__); }

#define LOGGER_WRITE_A2(Value) { \
	std::ostringstream logstream; logstream << Value; std::string logstring = logstream.str(); \
	SIMPLE_LOGGER::S_WriteA(0, logstring.c_str(), __FILE__, __LINE__, TRUE); }

#define LOGGER_WRITE_MEM(Value, Size) { \
	SIMPLE_LOGGER::S_WriteB(0, Value, Size, __FILE__, __LINE__); }
#else

#define LOGGER_WRITE_W(Value)					NULL;
#define LOGGER_WRITE_W2(Value)					NULL;
#define LOGGER_WRITE_A(Value)					NULL;
#define LOGGER_WRITE_A2(Value)					NULL;
#define LOGGER_WRITE_MEM(Value, Size)			NULL;

#endif

	void S_WriteA(int Index, const CHAR *Value, const CHAR* File, int Line, BOOL Flush = FALSE);
	void S_WriteW(int Index, const WCHAR *Value, const CHAR* File, int Line, BOOL Flush = FALSE);
	void S_WriteB(int Index, const BYTE *Value, int Size, const CHAR* File, int Line, BOOL Flush = FALSE);
};

实现文件如下:

#include "stdafx.h"
#include "SLogger.h"

#include <STDIO.H>
#include <SHARE.H>
#include <WTYPES.H>
#include <afxmt.h>

#define SL_MAX_LOG_LENGTH           800							// 日志记录最大存储字符数
#define SL_LAST_LOG_LENGTH          100							// 日志超长最大尾部存储字符
#define SL_MAX_FILE_SIZE            (1024 * 1024 * 5)			// 日志文件大小
#define SL_MAX_BACKUP_COUNT         2							// 最大备份几个日志文件(包括当前正在存储文件)
#define SL_FILEWRITER_COUNT         10							// 最大有十个日志对象存在

namespace SIMPLE_LOGGER {

	CCriticalSection m_oCrtSection;
	HANDLE m_hTimerHandle = NULL, m_hTimerQueue = NULL;
	class CFileWriter *m_oFileWriter[SL_FILEWRITER_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
	int m_iWriteCount[SL_FILEWRITER_COUNT] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
	VOID CALLBACK TimerAPCProc(PVOID lpParameter, BOOLEAN TimerOrWaitFired);

	void CreateTimer()
	{
		m_oCrtSection.Lock();
		if (NULL == m_hTimerQueue) {
			if (NULL != (m_hTimerQueue = CreateTimerQueue())) {
				CreateTimerQueueTimer(&m_hTimerHandle, m_hTimerQueue, (WAITORTIMERCALLBACK)TimerAPCProc, 
					NULL, 5000, 800, 0); // 800 *3 毫秒没有日志记录, 文件缓存写入磁盘。
			}
		}
		m_oCrtSection.Unlock();
	}

	void DeleteTimer()
	{
		m_oCrtSection.Lock();
		if (NULL != m_hTimerQueue) {
			DeleteTimerQueueTimer(m_hTimerQueue, m_hTimerHandle, INVALID_HANDLE_VALUE);
			DeleteTimerQueue(m_hTimerQueue);
			m_hTimerHandle = m_hTimerQueue = NULL;
		}
		m_oCrtSection.Unlock();
	}

	class CFileWriter
	{
	public:
		CFileWriter(int Index) : FileSize(0), hFileHandle(NULL), BkFileCount(SL_MAX_BACKUP_COUNT)
		{
#pragma warning(push)
#pragma warning(disable:4996)
			InitializeCriticalSection(&CritSection);
			WCHAR PathBuffer[MAX_PATH * 2] = { 0 };
			::GetModuleFileNameW(GetModuleHandle(NULL), PathBuffer, MAX_PATH);
			WCHAR *Temp = wcsrchr(PathBuffer, L'.');
			if (0 == Index) wmemcpy(Temp, L"_Log.txt", 8);
			else { wmemcpy(Temp, L"__Log.txt", 9); Temp[1] = L'0' + Index; }			
			wmemcpy(FullPathName, PathBuffer, MAX_PATH);
			Temp = wcsrchr(PathBuffer, L'\\');
			wcscpy(FileName, Temp + 1); Temp[1] = 0;
			wcscpy(FolderName, PathBuffer);
			do { swprintf_s(PathBuffer, L"%s%d_%s", FolderName, BkFileCount - 1, FileName); }
			while(!FileExisted(PathBuffer) && --BkFileCount > 0);
			Open();
#pragma warning(pop)
			m_oFileWriter[Index] = this;
			CreateTimer();
		}

		~CFileWriter(void) 
		{
			DeleteTimer();
			DeleteCriticalSection(&CritSection);
			Close();
		}

		bool FileExisted(WCHAR *FileName) 
		{
			DWORD dwAttricutes = ::GetFileAttributesW(FileName);
			return dwAttricutes != DWORD(-1) && ((dwAttricutes & FILE_ATTRIBUTE_DIRECTORY) == 0) ;
		}

		void Open()
		{
			if (NULL == hFileHandle) {
				if (NULL != (hFileHandle = _wfsopen(FullPathName, L"ab", _SH_DENYNO))) {
					fseek(hFileHandle, 0, SEEK_END);
					FileSize = ftell(hFileHandle);
				}
			}
		}

		void Close()
		{
			if (NULL != hFileHandle) {
				fclose(hFileHandle);
				hFileHandle = NULL;
			}			
		}

		void Write(const char *Value, const char* File, int Line, BOOL Flush)
		{
			if (SL_MAX_FILE_SIZE < FileSize) FileBackup();
			if (NULL != hFileHandle) {
				SYSTEMTIME Time;
				GetLocalTime(&Time);
				FileSize += fprintf_s(hFileHandle,
					"%04d/%02d/%02d %02d:%02d:%02d %03d %s [%s %d]\r\n", 
					Time.wYear, Time.wMonth, Time.wDay, 
					Time.wHour, Time.wMinute, Time.wSecond, Time.wMilliseconds,
					Value, File, Line);
				if (Flush) fflush(hFileHandle);
			}
		}

		void FileBackup()
		{
			WCHAR BkFileName[MAX_PATH];
			if (SL_MAX_BACKUP_COUNT == BkFileCount) {
				WCHAR BkFileName2[MAX_PATH];
				swprintf_s(BkFileName2, L"%s%d_%s", FolderName, 0, FileName);
				DeleteFileW(BkFileName2);
				for (int i = 1; i < SL_MAX_BACKUP_COUNT; i++) {
					swprintf_s(BkFileName,  L"%s%d_%s", FolderName, i - 1, FileName);
					swprintf_s(BkFileName2, L"%s%d_%s", FolderName, i, FileName);
					_wrename(BkFileName2, BkFileName);
				}
				BkFileCount--;
			}
			Close();
			swprintf_s(BkFileName, L"%s%d_%s", FolderName, BkFileCount++, FileName);
			_wrename(FullPathName, BkFileName);
			Open();
		}

		LONG FileSize;
		UINT BkFileCount;
		FILE* hFileHandle;
		WCHAR FolderName[MAX_PATH];
		WCHAR FullPathName[MAX_PATH];
		WCHAR FileName[MAX_PATH];
		CRITICAL_SECTION CritSection;
	};

	VOID CALLBACK TimerAPCProc(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
	{
		static int WriteCount[SL_FILEWRITER_COUNT] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
		static int CheckCount[SL_FILEWRITER_COUNT] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
		for (int i = SL_FILEWRITER_COUNT - 1; i >= 0; i--) {
			if (NULL != m_oFileWriter[i] && 0 != m_iWriteCount[i]) {
				if (WriteCount[i] != m_iWriteCount[i]) {
					WriteCount[i] = m_iWriteCount[i];
					CheckCount[i] = 0;
				}
				else if (3 == ++CheckCount[i]) {
					EnterCriticalSection(&m_oFileWriter[i]->CritSection);
					fflush(m_oFileWriter[i]->hFileHandle);
					WriteCount[i] = m_iWriteCount[i] = CheckCount[i] = 0;
					LeaveCriticalSection(&m_oFileWriter[i]->CritSection);
				}
			}
		}
	}

	void WriteToInternal(int Index, const CHAR *Value, const CHAR* File, int Line, BOOL Flush)
	{
#define CREATE_LOG_OBJECT(type) {  static CFileWriter LogWriter(type); Writer = &LogWriter; }
		CFileWriter *Writer = NULL;
		switch (Index) {
		case 0: CREATE_LOG_OBJECT(Index); break;
		case 1:	CREATE_LOG_OBJECT(Index); break;
		case 2:	CREATE_LOG_OBJECT(Index); break;
		case 3:	CREATE_LOG_OBJECT(Index); break;
		case 4:	CREATE_LOG_OBJECT(Index); break;
		case 5:	CREATE_LOG_OBJECT(Index); break;
		case 6:	CREATE_LOG_OBJECT(Index); break;
		case 7:	CREATE_LOG_OBJECT(Index); break;
		case 8:	CREATE_LOG_OBJECT(Index); break;
		case 9:	CREATE_LOG_OBJECT(Index); break;
		default: ASSERT(FALSE);           return;
		}
		::EnterCriticalSection(&Writer->CritSection);
		try { 
			Writer->Write(Value, File, Line, Flush); 
		}
		catch (...) {}
		if (Flush) m_iWriteCount[Index] = 0;
		else m_iWriteCount[Index]++;
		::LeaveCriticalSection(&Writer->CritSection);
	}

	bool Format(const BYTE *Value, UINT Length, BYTE *HexBuff, UINT BuffLen)
	{
#define HextoAsc0(Value, Result) { if (Value < 0x0a) Result = Value + 0x30; else Result = Value + 0x37; }
#define HextoAsc1(Value, Result) { BYTE Temp = (Value >> 4) & 0x0f; HextoAsc0(Temp, Result[0]); Temp = Value & 0x0f; HextoAsc0(Temp, Result[1]); }
#define HextoAsc2 { HextoAsc1(Value[Read], (HexBuff + Write)); Write += 2; HexBuff[Write++] = ' '; }

		UINT Write = 0, Read = 0;
		const UINT LineCount = 75, HexCount = 8;
		while (Read < Length) {
			UINT Count = Read + HexCount;
			if (Count > Length) Count = Length;
			if (INT(BuffLen - Write - LineCount) <= 0)
				break;

			HexBuff[Write++] = '\r'; HexBuff[Write++] = '\n';
			Write += sprintf_s((char*)HexBuff + Write, 9, "0x%04X  ", Read);
			UINT Begin = Write, Begin2 = Read;
			for (Read; Read < Count; Read++)
				HextoAsc2(Value[Read], (HexBuff + Write));

			HexBuff[Write++] = ' ';
			Count = Read + HexCount;
			if (Count > Length) Count = Length;
			for (Read; Read < Count; Read++)
				HextoAsc2(Value[Read], (HexBuff + Write));

			UINT Fill = Begin + HexCount * 6 + 2 - Write;
			for (UINT j = 0; j < Fill; j++)
				HexBuff[Write++] = ' ';

			for (Begin2; Begin2 < Read; Begin2++) {
				BYTE Data = Value[Begin2];
				if (Data >= 32 && Data <= 126) HexBuff[Write++] = Data;
				else HexBuff[Write++] = '.';
			}
		}

		return true;
	} 

	void S_WriteA(int Index, const CHAR *Value, const CHAR* File, int Line, BOOL Flush)
	{
		if (NULL != Value) {
			size_t StrLen = strlen(Value);
			if (SL_MAX_LOG_LENGTH <= StrLen) {
				char Buffer[SL_MAX_LOG_LENGTH] = { 0 };
				int Second = SL_LAST_LOG_LENGTH, First = SL_MAX_LOG_LENGTH  - Second - 6;
				memcpy(Buffer, Value, First);
				Buffer[First] = ' '; Buffer[First + 1] = '.'; Buffer[First + 2] = '.'; 
				Buffer[First + 3] = '.'; Buffer[First + 4] = ' ';
				memcpy(Buffer + First + 5, Value + (StrLen - Second), Second);
				WriteToInternal(Index, Buffer, File, Line, Flush);
			}
			else
				WriteToInternal(Index, Value, File, Line, Flush);
		  }
	}

	void S_WriteW(int Index, const WCHAR *Value, const CHAR* File, int Line, BOOL Flush)
	{
		if (NULL != Value) {
			char Buffer[SL_MAX_LOG_LENGTH] = { 0 };
			if (0 == WideCharToMultiByte(CP_ACP, 0, Value, -1, Buffer, SL_MAX_LOG_LENGTH - 1, NULL, NULL)) {
				char *Ellipsis = Buffer + (SL_MAX_LOG_LENGTH - 4);
				Ellipsis[0] = '.'; Ellipsis[1] = '.'; Ellipsis[2] = '.';
			}
			WriteToInternal(Index, Buffer, File, Line, Flush);
		}
	}

	void S_WriteB(int Index, const BYTE *Value, int Size, const CHAR* File, int Line, BOOL Flush)
	{
		if (NULL != Value) {
			char Buffer[SL_MAX_LOG_LENGTH] = { 0 };
			Format(Value, Size, (BYTE*)Buffer, SL_MAX_LOG_LENGTH - 1);
			S_WriteA(Index, Buffer, File, Line, Flush);
		}
	}
};

 

© 著作权归作者所有

共有 人打赏支持
g
粉丝 1
博文 1
码字总数 1283
作品 0
广州
STL,ATL,WTL的联系与区别

STL,ATL,WTL的联系与区别 STL 即 Standard Template Library STL(标准模板库)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时...

IMGTN
2012/06/04
0
0
关键词: 和

关键词:< iostream > 和 < iostream.h > 你写程序的时候,用< iostream >还是< iostream.h >? 你知道它们有什么区别么?还是认为他们根本就是一样的? 下面听我给你吹(文中纯属个人言论,...

AlphaJay
2010/06/21
0
0
STL,ATL,WTL之间的联系和区别

STL即 Standard Template Library (标准模板库) STL是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。现在虽说它...

AlphaJay
2010/06/28
0
0
看完这 7 条,模拟 C++ 新功能只是一个小目标!

但是,即使你无法使用这些功能,也不一定要放弃它们的好处。至少不用放弃全部。 有一些方法可以使用代码中新功能的思路,更准确地传达你的意图。 当然,这些方法肯定不如使用新版本C++本身的...

CSDN资讯
09/08
0
0
wxWidgets与其他工具库的比较(下)

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。 GTK+ www.gtk.org; http://www.gtkmm.org); Kylix Lazarus Ultimate++ http:...

nardoo
2012/09/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

arcgis jsapi接口入门系列(2):图层基础操作

//图层相关demo layerFun: function () { //获取地图的所有图层(不包括的图层类型:底图图层(basemaps)) let layers = this.map.layers; ...

canneljls
9分钟前
1
0
MySQL忘记root密码--不重启mysqd重置root密码

先提个问题:如何不重启mysqld,且没有权限修改用户账号和权限的情况下,如何重新设置root密码?不知道没关系,在此之前我也是不知道如何操作的,先看看下面的几种重置root密码的方法。 1、s...

IT--小哥
11分钟前
1
0
php7不再支持HTTP_RAW_POST_DATA,微信支付$GLOBALS[‘HTTP_RAW_POST_DATA’]获取不到数据,

升级到php7后, 发现旧的web系统有些问题, 查看后才发现原来是php7不再支持HTTP_RAW_POST_DATA 原来系统一些地方, 使用$GLOBALS[‘HTTP_RAW_POST_DATA’]来获取数据, 在php7里无法获取了 ...

15834278076
12分钟前
1
0
Android--拨打电话功能

Intent callIntent = new Intent(); callIntent.setAction(Intent.ACTION_DIAL); callIntent.setData(Uri.parse("tel:" + "4008823823")......

lanyu96
19分钟前
1
0
iOS多种刷新样式、音乐播放器、仿抖音视频、旅游App等源码

iOS精选源码 企业级开源项目,模仿艺龙旅行App 3D立体相册,可以旋转的立方体 横竖屏切换工具,使用陀螺仪检测手机设备方向,锁屏状... Swift版Refresh(可以自定义多种样式)架构方面有所优化...

Android爱开源
23分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部