文档章节

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

g
 gzstyxb
发布于 2013/11/19 17:36
字数 1283
阅读 629
收藏 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
广州
私信 提问
更新整理本人所有博文中提供的代码与工具(C++,2013.11)

  为了更方便地管理博文中涉及的各种代码与工具资源,现在把这些资源迁移到 Google Code 中,有兴趣者可前往下载。 C++ 1、《通用高性能 Windows Socket 组件 HP-Socket v3.0.2 正式发布》...

伤神小怪兽
2013/11/26
1K
19
更新整理本人所有博文中提供的代码与工具(C++,2013.08)

  为了更方便地管理博文中涉及的各种代码与工具资源,现在把这些资源迁移到 Google Code 中,有兴趣者可前往下载。 C++ 1、《通用高性能 Windows Socket 组件 HP-Socket v2.2.2 正式发布》...

伤神小怪兽
2013/08/18
1K
13
【★更新★】整理发布本人所有开源代码、工具及相关博文(C++)

  为了更方便地管理博文中涉及的各种代码与工具资源,现在把这些资源迁移到 Google Code 中,有兴趣者可前往下载。 C++ 1、《【五一呈献】通用高性能 Windows Socket 组件 HP-Socket v2.1...

伤神小怪兽
2013/05/13
1K
9
更新整理本人所有博文中提供的代码与工具(C++,2014.09)

  为了更方便地管理博文中涉及的各种代码与工具资源,现在把这些资源迁移到 GitHub 中,有兴趣者可前往下载。 C++ 1、《通用高性能 Windows Socket 组件 HP-Socket v3.2.3 正式发布》 《基...

伤神小怪兽
2014/09/28
721
2
更新整理本人所有博文中提供的代码与工具(C++,2013.10)

  为了更方便地管理博文中涉及的各种代码与工具资源,现在把这些资源迁移到 Google Code 中,有兴趣者可前往下载。 C++ 1、《通用高性能 Windows Socket 组件 HP-Socket v2.2.3 正式发布》...

伤神小怪兽
2013/10/10
673
10

没有更多内容

加载失败,请刷新页面

加载更多

mybatis学习(2)

http://www.mybatis.org/spring/zh/factorybean.html 参考mybatis官网 Mybatis集成Spring: 使用Spring的IOC,将sqlSession(存在事物),交给Spring管理。 1.依赖jar包 <dependency> <g......

杨健-YJ
19分钟前
1
0
ES的性能优化

我们在很多场景下会用到ES帮助我们解决搜索问题,但是很多人了解只是停留在表面,如何深入的使用ES,并做针对性的性能优化呢? 批量提交 当大量的写任务时,可以采用批量提交的方案,但是需要...

春哥大魔王的博客
20分钟前
1
0
Linux下实现 OpenSSL 简单加密与解密字符串

场景 shell脚本中存在明文密码 客户要求禁止使用明文密码,密码做加密处理. 方案 在网上了解到了Linux OpenSSL加密解密工具 可以指定各种加密算法为字符,文件做加密处理. 加密的案例比较多,解...

linuxprobe16
24分钟前
1
0
解析Sharding-Sphere的SQL执行引擎

一、前言 Sharding-JDBC 是一款优秀的分库分表框架,从3.0开始,Sharding-JDBC更名为Sharding-Sphere,之前用Sharding-JDBC 2时,对于同库分表而言,sql执行是串行的,因为同数据源的connect...

冷血狂魔
26分钟前
1
0
Spring Cloud Stream消费失败后的处理策略(二):自定义错误处理逻辑

应用场景 上一篇《Spring Cloud Stream消费失败后的处理策略(一):自动重试》介绍了默认就会生效的消息重试功能。对于一些因环境原因、网络抖动等不稳定因素引发的问题可以起到比较好的作用...

程序猿DD
40分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部