日志类简单封装

在程序开发过程中,我们需要动态了解程序运行状况,以及排查问题时程序的调用流程,尤其是在多线程程序中,调用关系用日志记录下来比较重要,方便以后排查问题。以下是自己开发过程中封装的日志功能类。

common.h

#ifndef __COMMON__H_
#define __COMMON__H_
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <time.h>
#include "LocalDefine.h"
#include <string>
#include <iostream>
#include <stdint.h>
#include <map>
#include <vector>

#if defined(WIN32) || defined(_WIN32)
#include <io.h>
#include <Ws2tcpip.h>
#include <winsock2.h>  
#include <windows.h>
#include <process.h>  
#include <sys/timeb.h>
#elif  __linux__
#include<stdarg.h>
#include <sys/time.h>
#include <unistd.h>
#include <pthread.h>
#include <netinet/in.h>  
#include <sys/socket.h>  
#include <sys/types.h>   
#include <arpa/inet.h> 
#include <errno.h>  
#endif

#endif

LocalDefine.h

#ifndef __LOCALDEFINE__H_
#define __LOCALDEFINE__H_

#if defined(WIN32) || defined(_WIN32)
#elif  __linux__
typedef unsigned long       DWORD;
typedef unsigned short      WORD;
typedef long LONG;
#define INFINITE            0xFFFFFFFF

typedef struct tagBITMAPFILEHEADER {
	WORD    bfType;
	DWORD   bfSize;
	WORD    bfReserved1;
	WORD    bfReserved2;
	DWORD   bfOffBits;
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{
	DWORD      biSize;
	LONG       biWidth;
	LONG       biHeight;
	WORD       biPlanes;
	WORD       biBitCount;
	DWORD      biCompression;
	DWORD      biSizeImage;
	LONG       biXPelsPerMeter;
	LONG       biYPelsPerMeter;
	DWORD      biClrUsed;
	DWORD      biClrImportant;
} BITMAPINFOHEADER;
#endif


#if defined(WIN32) || defined(_WIN32)
#elif  __linux__
#define _TRUNCATE ((size_t)-1)
#define _strdup	strdup
#endif

struct systemtime_t
{
	int tmsec;     /* seconds after the minute - [0,59] */
	int tmmin;     /* minutes after the hour - [0,59] */
	int tmhour;    /* hours since midnight - [0,23] */
	int tmmday;    /* day of the month - [1,31] */
	int tmmon;     /* months since January - [0,11] */
	int tmyear;    /* years since 1900 */
	int tmwday;    /* days since Sunday - [0,6] */
	int tmyday;    /* days since January 1 - [0,365] */
	int tmisdst;   /* daylight savings time flag */
	int tmmilliseconds;/*milliseconds after the sec[0,1000]*/
};

struct len_str
{
	unsigned char* pStr;
	size_t iLen;
};
#endif

在日志中需要用到的功能函数封装如下

#ifndef __UTIL__H_
#define __UTIL__H_
#include <algorithm>
#include "common.h"

//mem
#define DOFREE(X) do{if(nullptr != X) {free(X); X = nullptr;}}while(0)
#define DODELETE(X) do{if(nullptr != X) {delete X; X = nullptr;}}while(0)
#define BZERO(X) memset(&X, 0, sizeof(X))
void* do_malloc(size_t iLen);

//time
struct systemtime_t get_now_time();
uint64_t get_time_ms();	//获取时间毫秒级
void sleep_ms(DWORD dwMillions);

//thread
DWORD get_thread_id_self();
long atomic_change(volatile long* value, int off);

//strings
bool str_cmp(const char* pStr1, const char* pStr2, bool bIgnoreCase);
int safe_snprintf(char * _DstBuf, size_t _SizeInBytes, size_t _MaxCount, const char * _Format, ...);
bool str_start_with(const std::string& str, const std::string& prefix);
bool str_end_with(const std::string& str, const std::string& suffix);
bool str_cmp_nocase(std::string str1, std::string str2);
std::string& str_ltrim(std::string& str);
std::string& str_rtrim(std::string& str);
std::string& str_trim(std::string& str);
std::string str_2_lower(std::string& str);
std::string str_2_upper(std::string& str);
wchar_t* char_2_wchar(const char* pStr);
char* wchar_2_char(const wchar_t* pStr);
int split_str(std::string strSource, std::string strSep, std::vector<std::string>& vecRet);

//files
FILE* safe_open_file(const char* pFileName, const char* pMode);
len_str get_bmp(const void* pBmp, int width, int height, int bitCount);
const long get_file_len(const char* pFileName, const char* pMode);
size_t file_write(const char* pFileName, const char* pMode, const unsigned char* pData, const size_t iLen);
size_t file_read(const char* pFileName, const char* pMode, unsigned char* pData, const size_t iLen, const long lOffset);
char* file_read(const char* pFileName, const char* pMode, size_t& lLen);
std::string get_app_path();
bool file_exits(const char*  strFileName);
bool directory_exists(const char* strDirectory);
int make_dir(const char* path);	//创建目录
int make_dirs(const char* path);	//创建多层目录
const char* get_flietype(const char *pFileName);

//network
int init_platform();
int uninit_platform();

//error
void perror_desc(const char* pStr);
#endif



#include "util.h"

void* do_malloc(size_t iLen)
{
	if (iLen <= 0)
	{
		return nullptr;
	}

	void* pRet = nullptr;
	while (nullptr == pRet)
	{
		pRet = malloc(iLen);
	}

	memset(pRet, 0, iLen);
	
#if defined(WIN32) || defined(_WIN32)
	fprintf(stderr, "malloc mem:%I64u\n", iLen);
#elif  __linux__
	fprintf(stderr, "malloc mem:%llu\n", iLen);
#endif
	return pRet;
}

const char* get_flietype(const char *pFileName)
{
	int n = (int)strlen(pFileName);

	if (n < 5)
		return nullptr;

	if (!strcmp(&pFileName[n - 4], ".ico"))
		return "image/x-icon";

	if (!strcmp(&pFileName[n - 4], ".png"))
		return "image/png";

	if (!strcmp(&pFileName[n - 5], ".html"))
		return "text/html";

	if (!strcmp(&pFileName[n - 4], ".css"))
		return "text/css";

	if (!strcmp(&pFileName[n - 3], ".js"))
		return "text/javascript";

	return nullptr;
}

uint64_t get_time_ms()
{
	uint64_t iRet = 0;
#if defined(WIN32) || defined(_WIN32)
	iRet = GetTickCount();
#elif  __linux__
	struct timeval current;
	gettimeofday(&current, nullptr);
	iRet = (uint64_t)(current.tv_sec * 1000) + current.tv_usec/1000;
#endif

	return iRet;
}

void sleep_ms(DWORD dwMillions)
{
#if defined(WIN32) || defined(_WIN32)
	Sleep(dwMillions);
#elif  __linux__
	usleep(dwMillions * 1000);
#endif
}

struct systemtime_t get_now_time()
{
	struct systemtime_t stRet;
	time_t rawtime;
	struct tm tmnow;
#if defined(WIN32) || defined(_WIN32)
	time(&rawtime);
	localtime_s(&tmnow, &rawtime);
	struct timeb tp;
	ftime(&tp);
	stRet.tmmilliseconds = tp.millitm;
#elif  __linux__
	struct timeval tv_now;
	gettimeofday(&tv_now, nullptr);
	rawtime = (time_t)tv_now.tv_sec;
	
	localtime_r(&rawtime, &tmnow);
	stRet.tmmilliseconds = static_cast<int>(tv_now.tv_usec);
#endif

	stRet.tmyear = tmnow.tm_year + 1900;
	stRet.tmmon = tmnow.tm_mon + 1;
	stRet.tmmday = tmnow.tm_mday;
	stRet.tmhour = tmnow.tm_hour;
	stRet.tmmin = tmnow.tm_min;
	stRet.tmsec = tmnow.tm_sec;
	stRet.tmwday = tmnow.tm_wday;
	stRet.tmyday = tmnow.tm_yday;
	stRet.tmisdst = tmnow.tm_isdst;
	
	return stRet;
}

DWORD get_thread_id_self()
{
	DWORD iRet = 0;
#if defined(WIN32) || defined(_WIN32)
	iRet = ::GetCurrentThreadId();
#elif  __linux__
	iRet = pthread_self();
#endif

	return iRet;
}

long atomic_change(volatile long* value, int off)
{
  long lRet = 0;
	if (nullptr != value)
	{
#ifdef _WIN32
    lRet = InterlockedExchangeAdd(value, off);
#elif  __linux__
    lRet = __sync_fetch_and_add(value, off);
#endif
	}

  return lRet;
}

int split_str(std::string strSource, std::string strSep, std::vector<std::string>& vecRet)
{
    size_t i = 0;
    vecRet.clear();
    while (i < strSource.size()) {
        size_t iPos = strSource.find(strSep, i);
        if (iPos == std::string::npos) {
            vecRet.push_back(strSource.substr(i));
            break;
        }
        else {
            vecRet.push_back(strSource.substr(i, iPos - i));
            i = iPos + strSep.size();
        }
    }

    return (int)vecRet.size();
}

bool str_cmp(const char* pStr1, const char* pStr2, bool bIgnoreCase)
{
	if (pStr1 == pStr2)
	{
		return true;
	}

	if (nullptr == pStr1 || nullptr == pStr2)
	{
		return false;
	}

	size_t iLen = strlen(pStr1);
	if (iLen != strlen(pStr2))
	{
		return false;
	}

	for (int i = 0; i <= iLen; ++i)
	{
		char c1 = pStr1[i];
		char c2 = pStr2[i];
		if (bIgnoreCase)
		{
			c1 = toupper(c1);
			c2 = toupper(c2);
		}

		if (c1 != c2)
		{
			return false;
		}
	}

	return true;
}

int safe_snprintf(char * _DstBuf, size_t _SizeInBytes, size_t _MaxCount, const char * _Format, ...)
{
	int iRet = 0;
	va_list ap;
	va_start(ap, _Format);
#if defined(WIN32) || defined(_WIN32)
	iRet = vsnprintf_s(_DstBuf, _SizeInBytes, _MaxCount, _Format, ap);
#elif  __linux__
	iRet = vsnprintf(_DstBuf, _MaxCount, _Format, ap);
#endif
	va_end(ap);
	return iRet;
}

bool str_start_with(const std::string& str, const std::string& prefix)
{
	if (prefix.length() > str.length())
	{
		return false;
	}

	if (memcmp(str.c_str(), prefix.c_str(), prefix.length()) == 0) 
	{
		return true;
	}

	return false;
}

bool str_end_with(const std::string& str, const std::string& suffix)
{
	if (suffix.length() > str.length())
	{
		return false;
	}

	return (str.substr(str.length() - suffix.length()) == suffix);
}

std::string& str_ltrim(std::string& str) 
{ // NOLINT
	std::string::iterator it = find_if(str.begin(), str.end(), (int(*)(int))isspace);
	str.erase(str.begin(), it);
	return str;
}

std::string& str_rtrim(std::string& str) 
{ // NOLINT
	std::string::reverse_iterator it = find_if(str.rbegin(),
		str.rend(), (int(*)(int))isspace);

	str.erase(it.base(), str.end());
	return str;
}

std::string& str_trim(std::string& str) 
{ // NOLINT
	return str_rtrim(str_ltrim(str));
}

std::string str_2_lower(std::string& str)
{
	std::string strRet = str;
	transform(strRet.begin(), strRet.end(), strRet.begin(), (int(*)(int))tolower);
	return strRet;
}

std::string str_2_upper(std::string& str)
{
	std::string strRet = str;
	transform(strRet.begin(), strRet.end(), strRet.begin(), (int(*)(int))toupper);
	return strRet;
}

bool str_cmp_nocase(std::string str1, std::string str2)
{
	std::string strTmp1 = str_2_upper(str1);
	std::string strTmp2 = str_2_upper(str2);

	return strTmp1 == strTmp2;
}

wchar_t* char_2_wchar(const char* pStr)
{
	wchar_t* pRet = nullptr;
	if (nullptr != pStr)
	{
		size_t iLen = strlen(pStr);
		if (iLen > 0)
		{
			iLen += 1;
			fprintf(stderr, "char_2_wchar malloc\n");
			pRet = (wchar_t*)do_malloc(iLen * sizeof(wchar_t));
			if (nullptr != pRet)
			{
#if defined(WIN32) || defined(_WIN32)
				size_t converted = 0;
				mbstowcs_s(&converted, pRet, iLen, pStr, _TRUNCATE);
#elif  __linux__
				mbstowcs(pRet, pStr, iLen - 1);
#endif	
			}	
		}
	}

	return pRet;
}

char* wchar_2_char(const wchar_t* pStr)
{
	char* pRet = nullptr;
	if (nullptr != pStr)
	{
		size_t iLen = wcslen(pStr);
		if (iLen > 0)
		{
			iLen += 1;
			fprintf(stderr, "wchar_2_char malloc\n");
			pRet = (char*)do_malloc(iLen * sizeof(char));
			if (nullptr != pRet)
			{
#if defined(WIN32) || defined(_WIN32)
				size_t converted = 0;
				wcstombs_s(&converted, pRet, iLen, pStr, _TRUNCATE);
#elif  __linux__
				wcstombs(pRet, pStr, iLen - 1);
#endif	
			}
		}
	}

	return pRet;
}

const long get_file_len(const char* pFileName, const char* pMode)
{
	long lRet = 0;
	FILE *pFile = safe_open_file(pFileName, pMode);
	if (nullptr != pFile)
	{
		fseek(pFile, 0L, SEEK_END);
		lRet = ftell(pFile);
		fclose(pFile);
	}
	
	return lRet;
}

size_t file_write(const char* pFileName, const char* pMode, const unsigned char* pData, const size_t iLen)
{
	size_t iWrite = 0;
	do
	{
		if (nullptr == pData || iLen <= 0)
		{
			break;
		}

		FILE *pFile = safe_open_file(pFileName, pMode);
		if (nullptr != pFile)
		{
			while (iWrite < iLen)
			{
				iWrite += fwrite((void*)(pData + iWrite), sizeof(unsigned char), iLen - iWrite, pFile);
			}
			fclose(pFile);
		}
	} while (0);

	return iWrite;
}

size_t file_read(const char* pFileName, const char* pMode, unsigned char* pData, const size_t iLen, const long lOffset)
{
	size_t iRead = 0;
	do
	{
		if (nullptr == pData || iLen <= 0)
		{
			break;
		}

		FILE *pFile = safe_open_file(pFileName, pMode);
		if (nullptr != pFile)
		{
			if (fseek(pFile, lOffset, SEEK_SET) != 0)
			{
				break;
			}

			while (iRead < iLen && !feof(pFile))
			{
				iRead += fread((void*)(pData + iRead), sizeof(unsigned char), 1, pFile);
			}
			fclose(pFile);
		}
	} while (0);

	return iRead;
}

char* file_read(const char* pFileName, const char* pMode, size_t& lLen)
{
	char* pRet = nullptr;
	lLen = get_file_len(pFileName, pMode);
	if (lLen > 0)
	{
		pRet = (char*)do_malloc(lLen);
		if (pRet != nullptr)
		{
			FILE *pFile = safe_open_file(pFileName, pMode);
			if (nullptr != pFile)
			{
				size_t iRead = 0;
				while (iRead < lLen && !feof(pFile))
				{
					iRead += fread((void*)(pRet + iRead), sizeof(char), lLen - iRead, pFile);
				}
				fclose(pFile);
			}
		}
	}

	return pRet;
}

bool file_exits(const char*  strFileName)
{
	bool bRet = false;
#if defined(WIN32) || defined(_WIN32)
	DWORD dwRet = GetFileAttributesA(strFileName);
	bRet = (dwRet != INVALID_FILE_ATTRIBUTES) && (!(dwRet & FILE_ATTRIBUTE_DIRECTORY));
#elif  __linux__
	bRet = (access(strFileName, F_OK) == 0);
#endif
	return bRet;
}

bool directory_exists(const char* strDirectory)
{
	bool bRet = false;
#if defined(WIN32) || defined(_WIN32)
	DWORD dwRet = GetFileAttributesA(strDirectory);
	bRet = (dwRet != INVALID_FILE_ATTRIBUTES) && (dwRet & FILE_ATTRIBUTE_DIRECTORY);
#elif  __linux__
	struct stat sb;
	bRet = (lstat(strDirectory, &sb) == 0 && S_ISDIR(sb.st_mode));
#endif
	return bRet;
}

std::string get_app_path()
{
	std::string strRet = "";
#if defined(WIN32) || defined(_WIN32)
	char szExePath[MAX_PATH] = { 0 };
	GetModuleFileNameA(nullptr, szExePath, MAX_PATH);
	char *pstr = strrchr(szExePath, '\\');
	memset(pstr + 1, '\0', 1);
	strRet = szExePath;
#elif  __linux__
#define MAX_PATH 0x100
	char szFilePath[MAX_PATH];
	int cnt = readlink("/proc/self/exe", szFilePath, MAX_PATH);
	if (cnt < 0 || cnt >= MAX_PATH)
	{
		return strRet;
	}

	for (int i = cnt; i >= 0; --i)
	{
		if (szFilePath[i] == '/')
		{
			szFilePath[i + 1] = '\0';
			break;
		}
	}
	strRet = szFilePath;
#endif
	
	return strRet;
}

FILE* safe_open_file(const char* pFileName, const char* pMode)
{
	FILE* pRet = nullptr;
#if defined(WIN32) || defined(_WIN32)
	/*if (0 != fopen_s(&pRet, pFileName, pMode))
	{
		pRet = nullptr;
	}*/
	//fopen_s(&pRet,pFileName, pMode);
    pRet = fopen(pFileName, pMode);
#elif  __linux__
	pRet = fopen(pFileName, pMode);
#endif

	//设置非缓冲
	if (nullptr != pRet)
	{
		setvbuf(pRet, nullptr, _IONBF, 0);
	}

	return pRet;
}

len_str get_bmp(const void* pBmp, int width, int height, int bitCount)
{
	len_str stImg;
	memset(&stImg, 0, sizeof(len_str));
	if (nullptr == pBmp)
	{
		return stImg;
	}

	int bmp_size = width*height*(bitCount / 8);

	// 【写位图文件头】
	BITMAPFILEHEADER bmpHeader;
	bmpHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmp_size;    // BMP图像文件的大小
	bmpHeader.bfType = 0x4D42;    // 位图类别,根据不同的操作系统而不同,在Windows中,此字段的值总为‘BM’
	bmpHeader.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);            // BMP图像数据的偏移位置
	bmpHeader.bfReserved1 = 0;    // 总为0
	bmpHeader.bfReserved2 = 0;    // 总为0

	stImg.iLen = bmpHeader.bfSize;
	fprintf(stderr, "get_bmp malloc\n");
	stImg.pStr = (unsigned char*)do_malloc(sizeof(unsigned char)*bmpHeader.bfSize);
	if (nullptr == stImg.pStr)
	{
		stImg.iLen = 0;
		return stImg;
	}

	size_t iOffset = 0;
	memcpy(stImg.pStr, &bmpHeader, sizeof(bmpHeader));
	iOffset += sizeof(bmpHeader);

	BITMAPINFOHEADER bmiHeader;
	bmiHeader.biSize = sizeof(bmiHeader);                // 本结构所占用字节数,即sizeof(BITMAPINFOHEADER);
	bmiHeader.biWidth = width;                            // 位图宽度(单位:像素)
	bmiHeader.biHeight = height;                        // 位图高度(单位:像素)
	bmiHeader.biPlanes = 1;                                // 目标设备的级别,必须为1
	bmiHeader.biBitCount = bitCount;                    // 像素的位数(每个像素所需的位数,范围:1、4、8、24、32)
	bmiHeader.biCompression = 0;                        // 压缩类型(0:不压缩 1:BI_RLE8压缩类型 2:BI_RLE4压缩类型)
	bmiHeader.biSizeImage = bmp_size;                    // 位图大小(单位:字节)
	bmiHeader.biXPelsPerMeter = 0;                        // 水平分辨率(像素/米)
	bmiHeader.biYPelsPerMeter = 0;                        // 垂直分辨率(像素/米)
	bmiHeader.biClrUsed = 0;                            // 位图实际使用的彩色表中的颜色索引数
	bmiHeader.biClrImportant = 0;                        // 对图象显示有重要影响的颜色索引的数目

	// 【写位图信息头(BITMAPINFO的bmiHeader成员)】
	memcpy(stImg.pStr + iOffset, &bmiHeader, sizeof(bmiHeader));
	iOffset += sizeof(bmiHeader);

	// 【写像素内容】
	memcpy(stImg.pStr + iOffset, pBmp, bmp_size);

	return stImg;
}

int make_dir(const char* path)
{
	if (nullptr == path || strlen(path) <= 0)
	{
		return 1;
	}

	if(directory_exists(path))
	{
		return 0;
	}

#if defined(WIN32) || defined(_WIN32)
	if (!::CreateDirectoryA(path, nullptr))
	{
		return 1;
	}
#elif  __linux__
	if (mkdir(path, 0755) != 0)
	{
		fprintf(stderr, "mkdir %s failed(%s)\n", path, strerror(errno));
		return 1;
	}
#endif
	
	return 0;
}

int make_dirs(const char* path)
{
	size_t len = 0;
	if (nullptr == path || (len = strlen(path)) <= 0)
	{
		return 1;
	}

	fprintf(stderr, "make_dirs malloc\n");
	char* pTmp = (char*)do_malloc(len + 3);
	if (nullptr == pTmp)
	{
		return 1;
	}

	safe_snprintf(pTmp, len + 1, _TRUNCATE, "%s", path);

	for (int i = 0; i < (int)len; i++) 
	{
		if (pTmp[i] != '\\' && pTmp[i] != '/')
		{
			continue;
		}

		if (0 == i) {
			continue;
		}

		pTmp[i] = '\0';
		if (make_dir(pTmp) != 0)
		{
			break;
		}

		pTmp[i] = '/';
	}

	DOFREE(pTmp);

	return make_dir(path);
}

int init_platform()
{
	int iRet = 0;
#if defined(WIN32) || defined(_WIN32)
	WSADATA wsd;
	if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
	{
		iRet = 1;
	}
	_setmode(0, _O_BINARY);
	_setmode(1, _O_BINARY);
	_setmode(2, _O_BINARY);
#elif  __linux__
    signal(SIGPIPE, SIG_IGN);
#endif

	//输出非缓冲
	setvbuf(stdout, nullptr, _IONBF, 0);
	setvbuf(stderr, nullptr, _IONBF, 0);
	return iRet;
}

int uninit_platform()
{
#if defined(WIN32) || defined(_WIN32)
	WSACleanup();
#elif  __linux__
#endif

	return 0;
}

void perror_desc(const char* pStr)
{
#if defined(WIN32) || defined(_WIN32)
	wchar_t* pWstr = char_2_wchar(pStr);
	if (nullptr == pWstr)
	{
		return;
	}

	wchar_t* pBuf = nullptr;
	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK,
		nullptr,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		pBuf,
		0,
		nullptr))
	{
		wchar_t* pFormat = char_2_wchar("%s: %s");
		if (nullptr != pFormat)
		{
			fwprintf_s(stderr, pFormat, pWstr, pBuf);
			fflush(stderr);
			DOFREE(pFormat);
		}
		LocalFree((HLOCAL)pBuf);
	}
	else
	{
		wchar_t* pFormat = char_2_wchar("%s: unknown Windows error\n");
		if (nullptr != pFormat)
		{
			fwprintf_s(stderr, pFormat, pWstr);
			fflush(stderr);
			DOFREE(pFormat);
		}
	}

	DOFREE(pWstr);
#elif  __linux__
	if (nullptr != pStr)
	{
		perror(pStr);
	}
#endif
}

以下是日志库

#ifndef __LOGMANAGER__H_
#define __LOGMANAGER__H_
#include <cstdio>
#include <queue>
#include <string>
#include "singleton.h"
#include "CMutex.h"
#include "util.h"

enum LogType{ LOG_TYPE_SCREEN = 0, LOG_TYPE_FILE, LOG_TYPE_TEE, LOG_TYPE_MAX};
enum LogLevel{
	LOG_LEVEL_ERR = 0,
	LOG_LEVEL_DBG,
	LOG_LEVEL_FUNCTION,
	LOG_LEVEL_INFO,
	LOG_LEVEL_BLANK,
	LOG_LEVEL_MAX
};

#define MAX_PER_LOGFILE_SIZE 500*1024*1024	//单个日志文件的大小为500M
#define MAX_PER_LINE_LOG	2048	//一行日志最大缓存


typedef void(*log_cb)(int iLevel, const char *pData);

struct tagLogItem
{
	int iLevel;
	std::string strLog;
};

class CLogmanger : public CSingleton<CLogmanger>
{
	SINGLE_CLASS_INITIAL(CLogmanger);

public:
	int Init(int iType, int iLevel, const char* szDir, log_cb pLogCb=nullptr);
	~CLogmanger();
	void AddLogItem(int iLevel, const char *format, ...);
	int StopLog();
	int SetLogType(int iType);
	int SetLogLevel(int iLevel);
	int SetLogPath(const char* pPath);

private:
	int Check();
	FILE* GetFile();
	int PrintItem(tagLogItem& stLogItem);

private:
	int miType;
	int miLevel;
	unsigned long mlCount;
	bool mbInit;
	std::string mstrDir;
	FILE* mpFile;
	FILE* mpTmpFile;
	CMutex mcMutex;

  log_cb mpLogCb;
};

#define sLog CLogmanger::Instance()

#define LOG_ERR(fmt, ...) sLog->AddLogItem(LOG_LEVEL_ERR, "[ERROR](%s:%s:%d)[Thread:%u] " fmt, __FILE__, __FUNCTION__, __LINE__, (unsigned int)get_thread_id_self(), ##__VA_ARGS__)
#define LOG_DBG(fmt, ...) sLog->AddLogItem(LOG_LEVEL_DBG, "[DEBUG](%s:%s:%d)[Thread:%u] " fmt, __FILE__, __FUNCTION__, __LINE__, (unsigned int)get_thread_id_self(), ##__VA_ARGS__)
#define LOG_FUNCTION(fmt, ...) sLog->AddLogItem(LOG_LEVEL_FUNCTION, "[FUNCTION](%s)[Thread:%u] " fmt, __FUNCTION__, (unsigned int)get_thread_id_self(), ##__VA_ARGS__)
#define LOG_INFO(fmt, ...) sLog->AddLogItem(LOG_LEVEL_INFO, "[Thread:%u] " fmt, (unsigned int)get_thread_id_self(), ##__VA_ARGS__)
#define LOG_BLANK(fmt, ...) sLog->AddLogItem(LOG_LEVEL_BLANK, fmt, ##__VA_ARGS__)

#define ASSERT(expr) do{if (!(expr)){LOG_ERR("assert \"%s\" failed", #expr);}}while(0)
#define ASSERT_RET(expr) do{if (!(expr)){LOG_ERR("assert \"%s\" failed", #expr); return ; }}while(0)
#define ASSERT_RET_VALUE(expr, retval) do{if (!(expr)){LOG_ERR("assert \"%s\" failed", #expr); return retval; }}while(0)

#define ASSERT_ERR_MSG(expr, fmt, ...) \
do \
{ \
if (!(expr)) \
{ \
	LOG_ERR("assert \"%s\", msg:" fmt, #expr, ##__VA_ARGS__); \
} \
} while (0);

#define ASSERT_ERR_MSG_RET(expr, retval, fmt, ...) \
do \
{ \
if (!(expr)) \
{ \
	LOG_ERR("assert \"%s\", msg:" fmt, #expr, ##__VA_ARGS__); \
	return retval; \
} \
} while (0);

#endif

#include "CLogmanager.h"

#define RESET           0  
#define BRIGHT          1  
#define DIM             2  
#define UNDERLINE       4  
#define BLINK           5  
#define REVERSE         7  
#define HIDDEN          8  

#define BLACK           0  
#define RED             1  
#define GREEN           2  
#define YELLOW          3  
#define BLUE            4  
#define MAGENTA         5  
#define CYAN            6  
#define WHITE           7 

#if defined(WIN32) || defined(_WIN32)
#elif  __linux__
#define COLOR_PRINT_BEGIN	\033
#define COLOR_PRINT_END	\033[0m
#endif

CLogmanger::CLogmanger()
{
	miLevel = LOG_LEVEL_ERR;
	miType = LOG_TYPE_SCREEN;
	mlCount = 0;
	mstrDir = "";
	mbInit = false;
	mpFile = stdout;
	mpTmpFile = nullptr;
  mpLogCb = nullptr;
}

CLogmanger::~CLogmanger()
{
	if (nullptr != mpFile)
	{
		fclose(mpFile);
		mpFile = nullptr;
	}

	if (nullptr != mpTmpFile)
	{
		fclose(mpTmpFile);
		mpTmpFile = nullptr;
	}
}

FILE* CLogmanger::GetFile()
{
	if (mpTmpFile != nullptr  && mpTmpFile != stdout)
	{
		fclose(mpTmpFile);
		mpTmpFile = nullptr;
	}

	mpTmpFile = mpFile;
	if (miType == LOG_TYPE_FILE || miType == LOG_TYPE_TEE)
	{
		struct systemtime_t stNow = get_now_time();
		char szFileName[1000];
		safe_snprintf(szFileName, 1000, _TRUNCATE, "%02d-%02d-%02d-%02d-%02d-%02d.log", stNow.tmyear, stNow.tmmon, stNow.tmmday, stNow.tmhour, stNow.tmmin, stNow.tmsec);
		std::string strTmp = mstrDir;
		if (!str_end_with(strTmp, "\\") && !str_end_with(strTmp, "/"))
		{
			strTmp += "/";
		}

		strTmp += szFileName;
		FILE* pTmpTile = safe_open_file(strTmp.c_str(), "a+");
		if (nullptr == pTmpTile)
		{
			fprintf(stderr, "open  log file err:%s", strTmp.c_str());
			mpFile = stdout;
		}
		else
		{
			mpFile = pTmpTile;
		}
	}
	else
	{
		mpFile = stdout;
	}
	
	return mpFile;
}

int CLogmanger::Check()
{
	//文件过大创建新文件
	if (miType == LOG_TYPE_FILE || miType == LOG_TYPE_TEE)
	{
		if (mlCount >= MAX_PER_LOGFILE_SIZE)
		{
			mcMutex.Lock();
			if (mlCount >= MAX_PER_LOGFILE_SIZE)
			{
				mlCount = 0;
				GetFile();
			}
			mcMutex.UnLock();
		}
	}

	return 0;
}

int CLogmanger::SetLogType(int iType)
{
	if (!mbInit || iType < LOG_TYPE_SCREEN || iType >= LOG_TYPE_MAX)
	{
		return -1;
	}

	if (iType == miType)
	{
		return 0;
	}

	miType = iType;
	GetFile();

	return 0;
}

int CLogmanger::SetLogLevel(int iLevel)
{
	if (!mbInit || iLevel < LOG_LEVEL_ERR)
	{
		return -1;
	}

	miLevel = iLevel;

	return 0;
}

int CLogmanger::SetLogPath(const char* pPath)
{
	if (!mbInit || nullptr == pPath || str_cmp(pPath, mstrDir.c_str(), true))
	{
		return 1;
	}

	mstrDir = pPath;
	GetFile();
	return 0;
}

void CLogmanger::AddLogItem(int iLevel, const char *format, ...)
{
  if (nullptr != mpLogCb)
  {
    va_list arg;
    va_start(arg, format);
    int nPos = 0;
    char szBuf[MAX_PER_LINE_LOG];
#if defined(WIN32) || defined(_WIN32)
    nPos += vsnprintf_s(szBuf + nPos, MAX_PER_LINE_LOG - nPos - 1, _TRUNCATE, format, arg);
#elif  __linux__
    nPos += vsnprintf(szBuf + nPos, MAX_PER_LINE_LOG - nPos - 1, format, arg);
#endif

    if (nPos > MAX_PER_LINE_LOG - 1)
    {
      nPos = MAX_PER_LINE_LOG - 1;
    }

    if (nPos > 0)
    {
      szBuf[nPos] = '\0';
    }

    va_end(arg);
    mpLogCb(iLevel, szBuf);
    return;
  }

	if (iLevel > miLevel || iLevel > LOG_LEVEL_MAX || !mbInit)
	{
		return;
	}

	char szBuf[MAX_PER_LINE_LOG];
	memset(szBuf, 0, sizeof(szBuf));
	int nPos = 0;
	if (iLevel <= LOG_LEVEL_INFO)
	{
		struct systemtime_t stNow = get_now_time();
		nPos = safe_snprintf(szBuf, MAX_PER_LINE_LOG - 1, _TRUNCATE, "[%02d/%02d/%02d %02d:%02d:%02d.%06d] ", stNow.tmyear, stNow.tmmon, stNow.tmmday, stNow.tmhour, stNow.tmmin, stNow.tmsec, stNow.tmmilliseconds);
	}
	
	va_list ap;
	va_start(ap, format);
#if defined(WIN32) || defined(_WIN32)
	nPos += vsnprintf_s(szBuf + nPos, MAX_PER_LINE_LOG - nPos - 1, _TRUNCATE, format, ap);
#elif  __linux__
	nPos += vsnprintf(szBuf + nPos, MAX_PER_LINE_LOG - nPos - 1, format, ap);
#endif
	va_end(ap);

	if (nPos > MAX_PER_LINE_LOG - 1)
	{
		nPos = MAX_PER_LINE_LOG - 1;
	}
		
	if (nPos > 0)
	{
		szBuf[nPos] = '\0';
	}

	tagLogItem stLog;
	stLog.iLevel = iLevel;
	stLog.strLog = szBuf;
	PrintItem(stLog);
}

int CLogmanger::Init(int iType, int iLevel, const char* szDir, log_cb pLogCb)
{
  if (nullptr != pLogCb)
  {
    mpLogCb = pLogCb;
    return 0;
  }

	if (mbInit)
	{
		return 1;
	}

	miType = iType;
	miLevel = iLevel;
	if (nullptr != szDir && strlen(szDir) > 0 && !str_cmp(szDir, ".", true))
	{
		mstrDir = szDir;
	}
	else
	{
		mstrDir = get_app_path();
		mstrDir += "log";
	}

	if (make_dirs(mstrDir.c_str()))
	{
		fprintf(stderr, "make_dirs error!");
	}
	
	GetFile();

	if (nullptr == mpFile)
	{
		return 1;
	}

	mbInit = true;
	return 0;
}

int CLogmanger::StopLog()
{
	mbInit = false;

	return 0;
}

int CLogmanger::PrintItem(tagLogItem& stLogItem)
{
#if defined(WIN32) || defined(_WIN32)
	if (miType == LOG_TYPE_SCREEN && stLogItem.iLevel == LOG_LEVEL_ERR)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);
	}
#endif

	fprintf(mpFile, "%s\n", stLogItem.strLog.c_str());
	if (miType == LOG_TYPE_TEE)
	{
		fprintf(stdout, "%s\n", stLogItem.strLog.c_str());
	}

#if defined(WIN32) || defined(_WIN32)
	if (miType == LOG_TYPE_SCREEN && stLogItem.iLevel == LOG_LEVEL_ERR)
	{
		SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);
	}
#endif

	atomic_change((long*)&mlCount, (int)stLogItem.strLog.size());
	return Check();
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值