开发服务程序日志是必不可少的,又不想用log4g就自己写了个日志模块。下载连接走线程池,里面包含了日志,没要积分。

先看实现结果:在这里插入图片描述

直接上代码,有问题可以留言。

1、头文件.h

#ifndef _LOG_MODEL_H_      
#define _LOG_MODEL_H_

#include <string.h>
#include <string>
#include <stdio.h>
#include <pthread.h>
#include <queue>
#include <stdarg.h>
#include <unistd.h> 

using namespace std;

/* 红色对应 CRITICAL 与 ERROR log
 * 黄色对应 WARNING log
 * 绿色对应 INFO log
 * 蓝色对应 DEBUG log
 */
#define LOCAL_RED		"\033[31;1m"
#define LOCAL_YELLOW	"\033[0;33m"
#define LOCAL_GREEN		"\033[0;32m"
#define LOCAL_BULE		"\033[0;34m"
#define LOCAL_END		"\033[0m"

#define LOGSIEZ_1024		1024				// 日志大小
#define OPEN_LOG			1					// 声明是否打开日志输出
#define LOG_LEVEL			LOGLEVEL_DEBUG		// 声明当前程序的日志等级状态,只输出等级等于或高于该值的内容
#define LOG_SAVE			1					// 可补充日志保存功能
#define Sleep(nMills)		usleep(1000*nMills)	毫秒延时函数 仿window Sleep()
#define	ONE_MILLIS_1_MS		1
#define MaxFileSize_2M		2*1024*1024			//日志存储大小

typedef unsigned short      DWORD;

typedef enum{                       // 日志等级,越往下等级越高
	LOGLEVEL_DEBUG = 0,
	LOGLEVEL_INFO,
	LOGLEVEL_WARN,
	LOGLEVEL_ERROR,
}E_LOGLEVEL;

//日志结构体
typedef struct _LOG_INFO
{
	string  strLogInfo;			//日志内容
	int		nLogLev;			//日志等级

	_LOG_INFO()
	{
		strLogInfo = "";
		nLogLev = LOGLEVEL_INFO;

	}
}LOG_INFO;


/*
*
* 功能:日志组包。
* 返回值:
* 参1:日志等级,E_LOGLEVEL
* 参2:日志产生的文件。
* 参3:日志产生的方法名称。
* 参4:日志所在行数。
* 参5:日志内容。
*/
void log_Model(const int nLevel, const char* szFile, const char* szFun, const int nLine, const char *szfmt, ...);

// 宏定义,隐藏形参
//#define DP_LOG(nLevel, fmt...) log_Model(nLevel, __FILE__ ,__FUNCTION__, __LINE__, fmt) 
//修改成流形式 类似cout<<"123"<<"123"; 输出 123123
#define DP_LOG(nLevel, message){ \
	std::ostringstream t_stream;\
	t_stream  << message;\
	log_Model(nLevel, __FILE__ ,__FUNCTION__, __LINE__, (const char *)t_stream.str().c_str()) ;\
}

#define SWITCH_PRINT(fmt,...) do { \
	if (fmt >= LOG_LEVEL) { \
		switch (fmt) { \
		case LOGLEVEL_DEBUG: \
			printf(LOCAL_BULE); \
		break; \
		case LOGLEVEL_INFO: \
			printf(LOCAL_GREEN); \
		break; \
		case LOGLEVEL_WARN: \
			printf(LOCAL_YELLOW); \
		break; \
		case LOGLEVEL_ERROR: \
			printf(LOCAL_RED); \
		break; \
		default: \
			printf(LOCAL_GREEN); \
		break;\
	} \
	printf(__VA_ARGS__); \
	printf(LOCAL_END); \
	} \
} while(0)

class CLogModel
{
public:
	CLogModel();
	~CLogModel();

	/*
	* 功能:初始化日志对象。
	* 返回值:初始化成功返回true /失败返回false
	* 参1:日志路径
	*/
	bool IniLog(std::string strFilePath);

private:
	/*
	* 功能:创建日志文件,保存文件句柄。
	* 返回值:创建成功返回true /失败返回false
	* 参1:日志路径
	*/
	bool CreateFileAndGetHandle(std::string strFilePath);


private:
	FILE* m_logfile;
	std::string m_lastFileName;
	std::string m_lastFilePath;

	bool m_bQuitThread;
protected:
	//日志管理线程
	static void* LogManageThreadProc(void* p);
	//线程内核
	DWORD ManageCoreRun(); 
};
#endif

2、源文件.cpp

#include "logModel.h"
#include <time.h>

//日志队列  
typedef queue<LOG_INFO>				Que_LogInfo;

Que_LogInfo							g_LogInfo;
//日志锁	
pthread_mutex_t						g_LogMutex;
//全局锁初始化标志
bool								g_IniFlag=true;

//仿win32 GetTickCount接口
unsigned long GetCurrentSeconds()
{
	struct timespec ts;
	clock_gettime(CLOCK_MONOTONIC, &ts);
	return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}

char *logLevelGet(const int nLevel){  // 得到当前输入等级level的字符串
	if(nLevel == LOGLEVEL_DEBUG){
		return (char*)"DEBUG";
	}else if (nLevel == LOGLEVEL_INFO ){
		return (char*)"INFO";
	}else if (nLevel == LOGLEVEL_WARN ){
		return (char*)"WARN";
	}else if (nLevel == LOGLEVEL_ERROR ){
		return (char*)"ERROR";
	}else{
		return (char*)"UNKNOWN";
	}

}

void log_Model(const int nLevel, const char* szFile, const char* szFun, const int nLine, const char *szfmt, ...){ // 日志输出函数
	char szLog[LOGSIEZ_1024];
	LOG_INFO temp_log;
	//define修改这里直接赋值
	//va_list arg;
	//va_start(arg, szfmt);
	//char szBuf[LOGSIEZ_1024];     // 创建缓存字符数组
	//vsnprintf(szBuf, sizeof(szBuf), szfmt, arg);          // 赋值 ftm 格式的 arg 到 buf
	//va_end(arg);   
	                    
	sprintf(szLog,"[%s %s][%s]\t[%s] [%s] [%d]: %s \n",\
		__DATE__,__TIME__ ,logLevelGet(nLevel), szFile,szFun, nLine, szBuf);

	{//将数据放到日志队列 等待写日志
		pthread_mutex_lock(&g_LogMutex);
		temp_log.nLogLev = nLevel;
		temp_log.strLogInfo = szLog;
		g_LogInfo.push(temp_log);
		pthread_mutex_unlock(&g_LogMutex);
	}
}


CLogModel::CLogModel()
{
	m_logfile = NULL;
	m_lastFileName = "";
	m_lastFilePath = "";
	m_bQuitThread = false;
	
	//g_LogMutex全局锁初始化 
	if(g_IniFlag){
		pthread_mutex_init(&g_LogMutex, NULL);g_IniFlag=false;
	}
}


CLogModel::~CLogModel()
{

}

bool CLogModel::IniLog(std::string strFilePath)
{
	m_lastFilePath = strFilePath;
	if(CreateFileAndGetHandle(strFilePath)) {
		m_bQuitThread=true;
		pthread_t hThread;
		m_bQuitThread = true;
		bool ret = pthread_create(&hThread, NULL, LogManageThreadProc, this);
		if (ret != false){
			printf("hThread  err");
			return false;
		}
		return true;
	}
	printf("CreateFileAndGetHandle  err");
	return false;
}

bool CLogModel::CreateFileAndGetHandle(std::string strFilePath)
{
	char fname[256];
	memset(fname,0,sizeof(fname));

	char longtime[200];
	time_t t;
	time(&t);
	struct tm local = {0};
	localtime_r(&t, &local);
	sprintf(longtime,"%04d-%02d-%02d/", local.tm_year+1900,
		local.tm_mon+1, local.tm_mday);
	sprintf(fname,"%s/%s", strFilePath.c_str(),longtime);

	if(access(fname,0)!=0)
	{
		char cmdstr[256] = {0};
		sprintf(cmdstr,"mkdir -p %s",fname);
		system(cmdstr);
	}

	sprintf(fname,"%s%02d_%02d_%02d.log", fname,local.tm_hour, local.tm_min, local.tm_sec);

	bool retdate = false;
	unsigned long t_tick = GetCurrentSeconds();
	while(1)
	{
		m_logfile = fopen(fname, "ab");
		if(m_logfile)
		{
			m_lastFileName = fname;
			retdate=true;	
			break;
		}
		sleep(1);

		//超过2.5s 认定超时
		if (GetCurrentSeconds()-t_tick>2500)
		{
			break;
		}
	}
	return retdate;
}

void* CLogModel::LogManageThreadProc(void* p)
{
	CLogModel* pThis = (CLogModel*)p;
	pThis->ManageCoreRun();
	return NULL;
}


DWORD CLogModel::ManageCoreRun()
{
	//当前秒数
	DWORD  dwTimeStart = 0;
	while (m_bQuitThread)
	{
		Sleep(ONE_MILLIS_1_MS*10);
		pthread_mutex_lock(&g_LogMutex);
		int nQueLogCon = g_LogInfo.size();
		pthread_mutex_unlock(&g_LogMutex);

		if (nQueLogCon<=0)
			continue;

		LOG_INFO temp_log;
		pthread_mutex_lock(&g_LogMutex);
		temp_log = g_LogInfo.front();
		g_LogInfo.pop();
		pthread_mutex_unlock(&g_LogMutex);
		
		if(temp_log.nLogLev >= LOG_LEVEL){   // 判断当前日志等级,与程序日志等级状态对比
			//1、展示
			if(OPEN_LOG){
				SWITCH_PRINT(temp_log.nLogLev,temp_log.strLogInfo.c_str());
			}
			//2、存储
			if (LOG_SAVE){
				char showstr[LOGSIEZ_1024],showstr2[LOGSIEZ_1024];

				//看具体存储编码做转化,可以参考之前的GB2312ToUTF8博客
				//GB2312ToUTF8((char*)temp_log.strLogInfo.c_str(), strlen(temp_log.strLogInfo.c_str()), showstr2, sizeof(showstr2));

				char longtime[200];
				time_t t;
				time(&t);
				struct tm local = {0};
				localtime_r(&t, &local);
				sprintf(longtime,"%04d-%02d-%02d %02d:%02d:%02d", local.tm_year+1900,
					local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);

				m_logfile = fopen(m_lastFileName.c_str(), "ab");
				if(m_logfile){				
					if (ftell(m_logfile) < MaxFileSize_2M)   {// 判断文件大小
						//日期时间
						const char* pTemp = longtime;
						fwrite(pTemp, 1, strlen(pTemp), m_logfile);
						fwrite(" ", 1, 1, m_logfile);
						//内容
						fwrite(temp_log.strLogInfo.c_str(), 1, strlen(temp_log.strLogInfo.c_str()), m_logfile);
						fwrite(":", 1, 1, m_logfile);
						fwrite(showstr2, 1, strlen(showstr2), m_logfile);
						fwrite(" \r\n", 1, 3, m_logfile);
						fclose(m_logfile);
					}
					else{
						fclose(m_logfile);
						m_logfile = NULL;
						//超过5M 关闭当前,重新创建开一个flie
						CreateFileAndGetHandle(m_lastFilePath);
						//
						//可以在这里做删除之前的日志..
					}
				}
				else
				{
					CreateFileAndGetHandle(m_lastFilePath);
				}
			}
		}  
	}

	return 0;
}

3、main

#include <iostream>
#include	<unistd.h> 
#include "logModel.h"
using namespace std;



int main(int argc, char *argv[])
{
	char sz[] = "Hello, World!";	//Hover mouse over "sz" while debugging to see its contents
	cout << sz << endl;	//<================= Put a breakpoint here
	CLogModel m_log;
	m_log.IniLog("log");

	DP_LOG(LOGLEVEL_DEBUG,"this debug");
	DP_LOG(LOGLEVEL_INFO,"this info");
	DP_LOG(LOGLEVEL_WARN,"this warn");
	DP_LOG(LOGLEVEL_ERROR,"this err");
	DP_LOG(4,"this 4");

	while(1)
	{
		usleep(10000);
	}
	return 0;
}
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐