文档章节

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

g
 gzstyxb
发布于 2013/11/19 17:36
字数 1283
阅读 622
收藏 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
wxWidgets与其他工具库的比较(下)

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

nardoo
2012/09/06
0
0
[开源世界]从自动导出动态链接库接口看C++的缺点

自动导出动态链接库接口在C++编程中绝对是一件烦人的事情,因为你不得不大量的重复以下几个步骤: 1.加载动态链接库 2.定义导出函数指针定义 3.定义导出函数指针变量 4.从动态链接库中导出函...

梁欢
2013/10/21
0
2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

angular 解决其他电脑不能访问的问题。

ng serve --host 0.0.0.0 --disable-host-check

miaojiangmin
今天
1
0
优酷视频文件怎么转换格式

  以前在优酷上下载视频都只是在手机上观看,但随着科技的发展,对于视频的要求也逐渐增多,不再只是观看视频那么简单,在精彩的部分还会将其单独分割出来,然后进行视频剪辑,可以做出我们...

萤火的萤火
今天
0
0
数据结构:散列

在一个数据结构中查找key元素,用顺序查找、二分查找都需要经过一系列关键之比较才能查找到结果,平均查找长度与数据量有关,元素越多比较次数就越多。 如果根据元素的关键字就能知道元素的存...

京一
今天
1
0
Apache RocketMQ 正式开源分布式事务消息

近日,Apache RocketMQ 社区正式发布4.3版本。此次发布不仅包括提升性能,减少内存使用等原有特性增强,还修复了部分社区提出的若干问题,更重要的是该版本开源了社区最为关心的分布式事务消...

阿里云云栖社区
今天
33
0
使用JavaScript和MQTT开发物联网应用

如果说Java和C#哪个是最好的开发语言,无疑会挑起程序员之间的相互怒怼,那如果说JavaScript是动态性最好的语言,相信大家都不会有太大的争议。随着越来越多的硬件平台和开发板开始支持JavaS...

少年不搬砖老大徒伤悲
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部